/** * 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.engine.game; import aurelienribon.tweenengine.TweenAccessor; import com.google.inject.Inject; import com.google.inject.Singleton; import es.eucm.ead.engine.game.interfaces.TextProcessor; import es.eucm.ead.engine.gameobjects.sceneelements.SceneElementGO; import es.eucm.ead.engine.operators.OperatorFactory; import es.eucm.ead.model.elements.BasicElement; import es.eucm.ead.model.elements.conditions.Condition; 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.interfaces.features.Identified; import es.eucm.ead.tools.MathEvaluator.OperationResolver; import es.eucm.ead.tools.StringHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Singleton public class GameState extends ValueMap implements OperationResolver, TweenAccessor<ElementField> { private static Logger logger = LoggerFactory.getLogger(GameState.class); /** * Operator factory */ protected OperatorFactory operatorFactory; private TextProcessor textProcessor; /** * Map containing field watchers by element and variable */ private Map<String, List<FieldWatcher>> fieldWatchers; private Map<String, FieldGetter> fieldGetters; @Inject public GameState(StringHandler stringHandler) { super(stringHandler); this.operatorFactory = new OperatorFactory(this, stringHandler); this.textProcessor = new TextProcessor(operatorFactory, stringHandler); // Field watcher fieldWatchers = new HashMap<String, List<FieldWatcher>>(); fieldGetters = new HashMap<String, FieldGetter>(); } /** * Evaluates a condition, using the required evaluator * * @param <T> The actual condition class * @param condition The condition to be evaluated * @return The result of evaluating the condition according to the current * values of the game state */ public <T extends Condition> boolean evaluate(T condition) { if (condition == null) { return true; } return operatorFactory.operate(condition); } public <T extends Operation, S> S operate(T operation) { return operatorFactory.operate(operation); } public String processTextVars(String text, EAdList<Operation> operations) { return textProcessor.processTextVars(text, operations); } @Override public void setValue(String element, String varName, Object value) { if (!notifyWatchers(element, varName, value)) { super.setValue(element, varName, value); } } @Override public <S> S getValue(String element, String varName, S defaultValue) { S value = fieldGetters.containsKey(element) ? fieldGetters.get(element) .getField(element, varName, defaultValue) : null; return value == null ? super.getValue(element, varName, defaultValue) : value; } private <T> boolean notifyWatchers(String elementId, String varName, T value) { boolean handled = notifyWatchersImpl(fieldWatchers.get(elementId), elementId, varName, value); handled |= notifyWatchersImpl(fieldWatchers.get(elementId + "." + varName), elementId, varName, value); return handled; } private <T> boolean notifyWatchersImpl(List<FieldWatcher> list, String elementId, String varName, T value) { boolean handled = false; if (list != null) { for (FieldWatcher fw : list) { handled |= fw.setField(elementId, varName, value); } } return handled; } /** * Adds a field watcher that is notified every time the given field in the given element is * updated * * @param elementId the element's id */ public void addFieldWatcher(String elementId, String field, FieldWatcher fieldWatcher) { String key = elementId + (field == null ? "" : "." + field); List<FieldWatcher> list = fieldWatchers.get(key); if (list == null) { list = new ArrayList<FieldWatcher>(); fieldWatchers.put(key, list); } list.add(fieldWatcher); } /** * Adds a field watcher that is notified every time the element with the given id has any of its fields updated * @param elementId the element's id * @param fieldWatcher the field watcher */ public void addFieldWatcher(String elementId, FieldWatcher fieldWatcher) { addFieldWatcher(elementId, null, fieldWatcher); } /** * Removes a field watcher * * @param fieldWatcher the field watcher to remove */ public void removeFieldWatcher(FieldWatcher fieldWatcher) { for (List<FieldWatcher> l : fieldWatchers.values()) { l.remove(fieldWatcher); } } public void setFieldGetter(String elementId, FieldGetter fieldGetter) { this.fieldGetters.put(elementId, fieldGetter); } /** * Resets the game state to its initial state */ public void reset() { fieldWatchers.clear(); valuesMap.clear(); } public int countWatchers(String element) { List<FieldWatcher> list = fieldWatchers.get(element); return list == null ? 0 : list.size(); } public void addFieldWatcher(FieldWatcher fieldWatcher, BasicElement element) { addFieldWatcher(fieldWatcher, element, null); } public void addFieldWatcher(FieldWatcher fieldWatcher, BasicElement element, String field) { Identified i = maybeDecodeField(element); addFieldWatcher(i == null ? null : i.getId(), field, fieldWatcher); } public void removeGetter(SceneElementGO sceneElementGO) { fieldGetters.remove(sceneElementGO.getElement() + ""); } public interface FieldWatcher { /** * Call whenever the field is updated. * If true is returned, then the update has been handled by the watcher and it is not * necessary store the value in the value map. If false is returned, the value is stored * in the value map for subsequent queries */ <T> boolean setField(String elementId, String varName, T value); } public interface FieldGetter { /** * Called when something is asking for the value of the field. If null is returned, the value * returned is the one stored for the variable in the value map */ <T> T getField(String elementId, String varName, T defaultvalue); } }