/* * Copyright (c) Thomas Parker, 2009. * * This program 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 2.1 of the License, or (at your option) * any later version. * * 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package pcgen.cdom.facet; import java.util.List; import java.util.Set; import pcgen.base.formula.base.ScopeInstance; import pcgen.base.formula.base.VarScoped; import pcgen.cdom.base.CDOMObject; import pcgen.cdom.content.RemoteModifier; import pcgen.cdom.content.VarModifier; import pcgen.cdom.enumeration.CharID; import pcgen.cdom.enumeration.ListKey; import pcgen.cdom.facet.base.AbstractAssociationFacet; import pcgen.cdom.facet.event.DataFacetChangeEvent; import pcgen.cdom.facet.event.DataFacetChangeListener; import pcgen.cdom.facet.model.VarScopedFacet; import pcgen.cdom.inst.EquipmentHead; import pcgen.core.Equipment; /** * RemoteModifierFacet is a Facet that tracks remove Modifiers that have been * granted to a Player Character by looking for MODIFYOTHER: entries on * CDOMObjects added to/removed from the Player Character. */ public class RemoteModifierFacet extends AbstractAssociationFacet<CharID, RemoteModifier<?>, VarScoped> implements DataFacetChangeListener<CharID, VarScoped> { private ScopeFacet scopeFacet; private VarScopedFacet varScopedFacet; private SolverManagerFacet solverManagerFacet; @Override public void dataAdded(DataFacetChangeEvent<CharID, VarScoped> dfce) { CharID id = dfce.getCharID(); VarScoped vs = dfce.getCDOMObject(); /* * If this can have local variables, find what may have been modified by * previous objects */ for (RemoteModifier<?> rm : getSet(id)) { VarScoped src = get(id, rm); ScopeInstance inst = scopeFacet.get(id, src); processAdd(id, rm, vs, inst); if (vs instanceof Equipment) { Equipment e = (Equipment) vs; for (EquipmentHead head : e.getEquipmentHeads()) { processAdd(id, rm, head, inst); } } } /* * Look at what newly added object can modify on others */ if (vs instanceof CDOMObject) { ScopeInstance inst = scopeFacet.get(id, vs); List<RemoteModifier<?>> list = ((CDOMObject) vs).getListFor(ListKey.REMOTE_MODIFIER); if (list != null) { Set<? extends VarScoped> targets = varScopedFacet.getSet(id); for (RemoteModifier<?> rm : list) { set(id, rm, vs); //Apply to existing as necessary for (VarScoped obj : targets) { processAdd(id, rm, obj, inst); if (obj instanceof Equipment) { Equipment e = (Equipment) obj; for (EquipmentHead head : e.getEquipmentHeads()) { processAdd(id, rm, head, inst); } } } } } } } private <MT> void processAdd(CharID id, RemoteModifier<MT> rm, VarScoped vs, ScopeInstance src) { if (rm.getGrouping().contains(vs)) { VarModifier<MT> vm = rm.getVarModifier(); solverManagerFacet.addModifier(id, vm, vs, src); } } @Override public void dataRemoved(DataFacetChangeEvent<CharID, VarScoped> dfce) { CharID id = dfce.getCharID(); VarScoped vs = dfce.getCDOMObject(); /* * If this can have local variables, find what had been modified by * previous objects */ for (RemoteModifier<?> rm : getSet(id)) { VarScoped src = get(id, rm); ScopeInstance inst = scopeFacet.get(id, src); processRemove(id, rm, vs, inst); if (vs instanceof Equipment) { Equipment e = (Equipment) vs; for (EquipmentHead head : e.getEquipmentHeads()) { processRemove(id, rm, head, inst); } } } /* * Look at what newly added object can modify on others */ if (vs instanceof CDOMObject) { ScopeInstance inst = scopeFacet.get(id, vs); List<RemoteModifier<?>> list = ((CDOMObject) vs).getListFor(ListKey.REMOTE_MODIFIER); if (list != null) { Set<? extends VarScoped> targets = varScopedFacet.getSet(id); for (RemoteModifier<?> rm : list) { remove(id, rm); //RemoveFrom existing as necessary for (VarScoped obj : targets) { processRemove(id, rm, obj, inst); if (obj instanceof Equipment) { Equipment e = (Equipment) obj; for (EquipmentHead head : e.getEquipmentHeads()) { processRemove(id, rm, head, inst); } } } } } } } private <MT> void processRemove(CharID id, RemoteModifier<MT> rm, VarScoped vs, ScopeInstance src) { if (rm.getGrouping().contains(vs)) { VarModifier<MT> vm = rm.getVarModifier(); solverManagerFacet.removeModifier(id, vm, vs, src); } } public void setScopeFacet(ScopeFacet scopeFacet) { this.scopeFacet = scopeFacet; } public void setVarScopedFacet(VarScopedFacet varScopedFacet) { this.varScopedFacet = varScopedFacet; } public void setSolverManagerFacet(SolverManagerFacet solverManagerFacet) { this.solverManagerFacet = solverManagerFacet; } /** * Initializes the connections for ArmorProfFacet to other facets. * * This method is automatically called by the Spring framework during * initialization of the ArmorProfFacet. */ public void init() { varScopedFacet.addDataFacetChangeListener(this); } /* * In Ability: MODIFYOTHER:EQUIPMENT|GROUP=Martial|EqCritRange|ADD|1 * * In Global: * MODIFYOTHER:EQUIPMENT.PART|ALL|CritRange|SOLVE|value()+EqCritRange * |PRIORITY=10000 * * effectively we are solving APPLYTO:EQUIPMENT|PC[GROUP=Martial]|... * * EQUIPMENT ends up in the Modifier as stDef * * EqCritRange|ADD|1 also ends up in the VarModifier (as the varName and the * Modifier itself) * * type is getGroupClass() * * * * GROUP=Martial is static * * PC is dynamic and attached to a Facet * * list(PC) && list(GROUP=Martial) * * But what happens when something lands on the list? * * Then we need to circle around & load local vars... * * When New member of a certain VarID (e.g. Applied Equipment) Then take * that member and get the VariableStore Look up in the database all * VarModifiers to be applied merge VariableStore and VarModifiers... */ }