package com.planet_ink.coffee_mud.MOBS; import com.planet_ink.coffee_mud.core.interfaces.*; import com.planet_ink.coffee_mud.core.*; import com.planet_ink.coffee_mud.core.collections.*; import com.planet_ink.coffee_mud.Abilities.interfaces.*; import com.planet_ink.coffee_mud.Areas.interfaces.*; import com.planet_ink.coffee_mud.Behaviors.interfaces.*; import com.planet_ink.coffee_mud.CharClasses.interfaces.*; import com.planet_ink.coffee_mud.Commands.interfaces.*; import com.planet_ink.coffee_mud.Common.interfaces.*; import com.planet_ink.coffee_mud.Exits.interfaces.*; import com.planet_ink.coffee_mud.Items.interfaces.*; import com.planet_ink.coffee_mud.Libraries.interfaces.TrackingLibrary; import com.planet_ink.coffee_mud.Locales.interfaces.*; import com.planet_ink.coffee_mud.MOBS.interfaces.*; import com.planet_ink.coffee_mud.Races.interfaces.*; import java.util.*; /* Copyright 2001-2019 Bo Zimmerman Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ public class StdDeity extends StdMOB implements Deity { @Override public String ID() { return "StdDeity"; } protected int xpwrath = 100; protected String clericReqs = ""; protected String worshipReqs = ""; protected String serviceRitual = ""; protected String clericRitual = ""; protected String clericSin = ""; protected String clericPowerup = ""; protected String worshipRitual = ""; protected String worshipSin = ""; protected int rebukeCheckDown = 0; protected boolean norecurse = false; protected MOB blacklist = null; protected int blackmarks = 0; protected long lastBlackmark = 0; protected List<DeityTrigger> worshipTriggers = new Vector<DeityTrigger>(); protected List<DeityTrigger> worshipCurseTriggers= new Vector<DeityTrigger>(); protected List<DeityTrigger> clericTriggers = new Vector<DeityTrigger>(); protected List<DeityTrigger> serviceTriggers = new Vector<DeityTrigger>(); protected List<DeityTrigger> clericPowerTriggers = new Vector<DeityTrigger>(); protected List<DeityTrigger> clericCurseTriggers = new Vector<DeityTrigger>(); protected List<DeityPower> blessings = new SVector<DeityPower>(); protected List<DeityPower> curses = new SVector<DeityPower>(); protected List<Ability> powers = new SVector<Ability>(); protected Map<String, boolean[]>trigBlessingParts = new SHashtable<String, boolean[]>(); protected Map<String, Long> trigBlessingTimes = new SHashtable<String, Long>(); protected Map<String, boolean[]>trigPowerParts = new SHashtable<String, boolean[]>(); protected Map<String, Long> trigPowerTimes = new SHashtable<String, Long>(); protected Map<String, boolean[]>trigCurseParts = new SHashtable<String, boolean[]>(); protected Map<String, Long> trigCurseTimes = new SHashtable<String, Long>(); protected Map<String, boolean[]>trigServiceParts = new SHashtable<String, boolean[]>(); protected Map<String, Long> trigServiceTimes = new SHashtable<String, Long>(); protected List<WorshipService> services = new SVector<WorshipService>(); protected List<MOB> waitingFor = new SLinkedList<MOB>(); public StdDeity() { super(); username="a Mighty Deity"; setDescription("He is Mighty."); setDisplayText("A Mighty Deity stands here!"); basePhyStats().setWeight(700); basePhyStats().setAbility(200); basePhyStats().setArmor(0); basePhyStats().setAttackAdjustment(1000); basePhyStats().setDamage(1000); baseCharStats().setMyRace(CMClass.getRace("Spirit")); recoverPhyStats(); } private static class WorshipService { public MOB cleric = null; public Room room = null; public boolean serviceCompleted = false; public long startTime = System.currentTimeMillis(); public List<MOB> parishaners = new Vector<MOB>(); } private static class DeityPower { public Ability power; public boolean clericOnly; public DeityPower(final Ability A, final boolean clericsOnly) { power=A; clericOnly=clericsOnly; } } @Override protected void cloneFix(final MOB E) { super.cloneFix(E); if(E instanceof StdDeity) { worshipTriggers=new XVector<DeityTrigger>(((StdDeity)E).worshipTriggers); worshipCurseTriggers=new XVector<DeityTrigger>(((StdDeity)E).worshipCurseTriggers); clericTriggers=new XVector<DeityTrigger>(((StdDeity)E).clericTriggers); clericPowerTriggers=new XVector<DeityTrigger>(((StdDeity)E).clericPowerTriggers); clericCurseTriggers=new XVector<DeityTrigger>(((StdDeity)E).clericCurseTriggers); blessings=new XVector<DeityPower>(((StdDeity)E).blessings); curses=new XVector<DeityPower>(((StdDeity)E).curses); powers=new XVector<Ability>(((StdDeity)E).powers); trigBlessingParts=new XHashtable<String,boolean[]>(((StdDeity)E).trigBlessingParts); trigBlessingTimes=new XHashtable<String,Long>(((StdDeity)E).trigBlessingTimes); trigPowerParts=new XHashtable<String,boolean[]>(((StdDeity)E).trigPowerParts); trigPowerTimes=new XHashtable<String,Long>(((StdDeity)E).trigPowerTimes); trigCurseParts=new XHashtable<String,boolean[]>(((StdDeity)E).trigCurseParts); trigCurseTimes=new XHashtable<String,Long>(((StdDeity)E).trigCurseTimes); trigServiceParts=new XHashtable<String,boolean[]>(((StdDeity)E).trigServiceParts); trigServiceTimes=new XHashtable<String,Long>(((StdDeity)E).trigServiceTimes); } } @Override public String getClericRequirements() { return clericReqs; } @Override public void setClericRequirements(final String reqs) { clericReqs=reqs; } @Override public String getWorshipRequirements() { return worshipReqs; } @Override public void setWorshipRequirements(final String reqs) { worshipReqs=reqs; } @Override public String getClericRitual() { if(clericRitual.trim().length()==0) return "SAY Bless me "+name(); return clericRitual; } @Override public void setClericRitual(final String ritual) { clericRitual=ritual; parseTriggers(clericTriggers,ritual); } @Override public String getWorshipRitual() { if(worshipRitual.trim().length()==0) return "SAY Bless me "+name(); return worshipRitual; } @Override public void setWorshipRitual(final String ritual) { worshipRitual=ritual; parseTriggers(worshipTriggers,ritual); } @Override public String getServiceRitual() { return serviceRitual; } @Override public void setServiceRitual(String ritual) { if((ritual==null)||(ritual.length()==0)) ritual="SAY Bless us "+name()+"&wait 10&wait 10&SAY May "+name()+" bless you all&ALLSAY Amen.&SAY Go in peace"; serviceRitual=ritual; parseTriggers(serviceTriggers,ritual); } public String getTriggerDesc(final List<DeityTrigger> V) { if((V==null)||(V.size()==0)) return L("Never"); final StringBuffer buf=new StringBuffer(""); for(int v=0;v<V.size();v++) { final DeityTrigger DT=V.get(v); if(v>0) buf.append(", "+((DT.previousConnect==RitualConnector.AND)?L("and "):L("or "))); switch(DT.triggerCode) { case SAY: buf.append(L("the player should say '@x1'",DT.parm1.toLowerCase())); break; case READING: if(DT.parm1.equals("0")) buf.append(L("the player should read something")); else buf.append(L("the player should read '@x1'",DT.parm1.toLowerCase())); break; case TIME: buf.append(L("the hour of the day is @x1",DT.parm1.toLowerCase())); break; case PUTTHING: buf.append(L("the player should put @x1 in @x2",DT.parm1.toLowerCase(),DT.parm2.toLowerCase())); break; case BURNTHING: buf.append(L("the player should burn @x1",DT.parm1.toLowerCase())); break; case DRINK: buf.append(L("the player should drink @x1",DT.parm1.toLowerCase())); break; case EAT: buf.append(L("the player should eat @x1",DT.parm1.toLowerCase())); break; case INROOM: { if(DT.parm1.equalsIgnoreCase("holy") ||DT.parm1.equalsIgnoreCase("unholy") ||DT.parm1.equalsIgnoreCase("balance")) buf.append(L("the player should be in the deities room of infused @x1-ness.",DT.parm1.toLowerCase())); else { final Room R=CMLib.map().getRoom(DT.parm1); if(R==null) buf.append(L("the player should be in some unknown place")); else buf.append(L("the player should be in '@x1'",R.displayText(null))); } } break; case RIDING: buf.append(L("the player should be on @x1",DT.parm1.toLowerCase())); break; case CAST: { final Ability A=CMClass.findAbility(DT.parm1); if(A==null) buf.append(L("the player should cast '@x1'",DT.parm1)); else buf.append(L("the player should cast '@x1'",A.name())); } break; case EMOTE: buf.append(L("the player should emote '@x1'",DT.parm1.toLowerCase())); break; case RANDOM: buf.append(DT.parm1+"% of the time"); break; case WAIT: buf.append(L("wait @x1 seconds",""+((CMath.s_int(DT.parm1)*CMProps.getTickMillis())/1000))); break; case YOUSAY: buf.append(L("then you will automatically say '@x1'",DT.parm1.toLowerCase())); break; case OTHERSAY: buf.append(L("then all others will say '@x1'",DT.parm1.toLowerCase())); break; case ALLSAY: buf.append(L("then all will say '@x1'",DT.parm1.toLowerCase())); break; case CHECK: buf.append(CMLib.masking().maskDesc(DT.parm1)); break; case PUTVALUE: buf.append(L("the player should put an item worth at least @x1 in @x2",DT.parm1.toLowerCase(),DT.parm2.toLowerCase())); break; case PUTMATERIAL: { String material="something"; final int t=CMath.s_int(DT.parm1); RawMaterial.Material m; if(((t&RawMaterial.RESOURCE_MASK)==0) &&((m=RawMaterial.Material.findByMask(t))!=null)) material=m.desc().toLowerCase(); else if(RawMaterial.CODES.IS_VALID(t)) material=RawMaterial.CODES.NAME(t).toLowerCase(); buf.append(L("the player puts an item made of @x1 in @x2",material,DT.parm2.toLowerCase())); } break; case BURNMATERIAL: { String material="something"; final int t=CMath.s_int(DT.parm1); RawMaterial.Material m; if(((t&RawMaterial.RESOURCE_MASK)==0) &&((m=RawMaterial.Material.findByMask(t))!=null)) material=m.desc().toLowerCase(); else if(RawMaterial.CODES.IS_VALID(t)) material=RawMaterial.CODES.NAME(t).toLowerCase(); buf.append(L("the player should burn an item made of @x1",material)); } break; case BURNVALUE: buf.append(L("the player should burn an item worth at least @x1",DT.parm1.toLowerCase())); break; case SITTING: buf.append(L("the player should sit down")); break; case STANDING: buf.append(L("the player should stand up")); break; case SLEEPING: buf.append(L("the player should go to sleep")); break; } } return buf.toString(); } @Override public String getClericRequirementsDesc() { return L("The following may be clerics of @x1: @x2",name(),CMLib.masking().maskDesc(getClericRequirements())); } @Override public String getClericTriggerDesc() { if(numBlessings()>0) return L("The blessings of @x1 are placed upon @x2 clerics whenever the cleric does the following: @x3.",name(),charStats().hisher(),getTriggerDesc(clericTriggers)); return ""; } @Override public String getWorshipRequirementsDesc() { return L("The following are acceptable worshipers of @x1: @x2",name(),CMLib.masking().maskDesc(getWorshipRequirements())); } @Override public String getWorshipTriggerDesc() { if(numBlessings()>0) return L("The blessings of @x1 are placed upon @x2 worshippers whenever they do the following: @x3.",name(),charStats().hisher(),getTriggerDesc(worshipTriggers)); return ""; } @Override public String getServiceTriggerDesc() { return L("The services of @x1 are the following: @x2.",name(),getTriggerDesc(serviceTriggers)); } @Override public boolean okMessage(final Environmental myHost, final CMMsg msg) { if(!super.okMessage(myHost,msg)) return false; if((msg.targetMinor()==CMMsg.TYP_EXPIRE) &&(msg.target()==location()) &&(CMLib.flags().isInTheGame(this,true))) return false; else if(msg.amITarget(this)) switch(msg.targetMinor()) { case CMMsg.TYP_SERVE: if(msg.source().getMyDeity()==this) { msg.source().tell(L("You already worship @x1.",name())); if(msg.source().isMonster()) CMLib.commands().postSay(msg.source(),null,L("I already worship @x1.",msg.source().getMyDeity().name())); return false; } if(msg.source().getMyDeity()!=null) { msg.source().tell(L("You already worship @x1.",msg.source().getMyDeity().name())); if(msg.source().isMonster()) CMLib.commands().postSay(msg.source(),null,L("I already worship @x1.",msg.source().getMyDeity().name())); return false; } if(msg.source().charStats().getCurrentClass().baseClass().equalsIgnoreCase("Cleric")) { if(!CMLib.masking().maskCheck(getClericRequirements(),msg.source(),true)) { msg.source().tell(L("You are unworthy of serving @x1.",name())); if(msg.source().isMonster()) CMLib.commands().postSay(msg.source(),null,L("I am unworthy of serving @x1.",name())); return false; } } else if(!CMLib.masking().maskCheck(getWorshipRequirements(),msg.source(),true)) { msg.source().tell(L("You are unworthy of @x1.",name())); if(msg.source().isMonster()) CMLib.commands().postSay(msg.source(),null,L("I am unworthy of @x1.",name())); return false; } break; case CMMsg.TYP_REBUKE: if(!msg.source().getWorshipCharID().equals(Name())) { msg.source().tell(L("You do not worship @x1.",name())); return false; } break; } return true; } public synchronized void bestowBlessing(final MOB mob, final Ability blesingA) { final Room prevRoom; synchronized(this) { prevRoom=location(); } final Room targetRoom; synchronized(mob) { targetRoom=mob.location(); } targetRoom.bringMobHere(this,false); if(blesingA!=null) { final Vector<String> V=new Vector<String>(); if(blesingA.canTarget(Ability.CAN_MOBS)) { V.addElement(mob.name()+"$"); blesingA.invoke(this,V,mob,true,mob.phyStats().level()); } else if(blesingA.canTarget(Ability.CAN_ITEMS)) { Item I=mob.fetchWieldedItem(); if(I==null) I=mob.fetchHeldItem(); if(I==null) I=mob.fetchItem(null,Wearable.FILTER_WORNONLY,"all"); if(I==null) I=mob.fetchItem(null,Wearable.FILTER_UNWORNONLY,"all"); if(I==null) return; V.addElement("$"+I.name()+"$"); addItem(I); blesingA.invoke(this,V,I,true,mob.phyStats().level()); delItem(I); if(!mob.isMine(I)) mob.addItem(I); } else blesingA.invoke(this,mob,true,mob.phyStats().level()); } prevRoom.bringMobHere(this,false); if((prevRoom != location()) ||(!prevRoom.isInhabitant(this)) ||(targetRoom.isInhabitant(this))) { this.setLocation(prevRoom); prevRoom.addInhabitant(this); targetRoom.delInhabitant(this); } if(targetRoom!=prevRoom) { if(mob.getVictim()==this) mob.makePeace(true); if(getVictim()==mob) makePeace(true); } } public synchronized void bestowPower(final MOB mob, Ability Power) { if((mob.fetchAbility(Power.ID())==null) &&(CMLib.ableMapper().qualifyingLevel(mob,Power)<=0)) { Power=(Ability)Power.copyOf(); Power.setProficiency(CMLib.ableMapper().getMaxProficiency(mob,true,Power.ID())); Power.setSavable(false); mob.addAbility(Power); } } public synchronized void bestowCurse(final MOB mob, final Ability Curse) { final Room prevRoom; synchronized(this) { prevRoom=location(); } final Room targetRoom; synchronized(mob) { targetRoom=mob.location(); } targetRoom.bringMobHere(this,false); if(Curse!=null) { final Vector<String> V=new Vector<String>(); if(Curse.canTarget(Ability.CAN_MOBS)) { V.addElement(mob.location().getContextName(mob)); Curse.invoke(this,V,mob,true,mob.phyStats().level()); } else if(Curse.canTarget(Ability.CAN_ITEMS)) { Item I=mob.fetchWieldedItem(); if(I==null) I=mob.fetchHeldItem(); if(I==null) I=mob.fetchItem(null,Wearable.FILTER_WORNONLY,"all"); if(I==null) I=mob.fetchItem(null,Wearable.FILTER_UNWORNONLY,"all"); if(I==null) return; V.addElement("$"+I.name()+"$"); addItem(I); Curse.invoke(this,V,I,true,mob.phyStats().level()); delItem(I); if(!mob.isMine(I)) mob.addItem(I); } else Curse.invoke(this,mob,true,mob.phyStats().level()); } prevRoom.bringMobHere(this,false); if((prevRoom != location()) ||(!prevRoom.isInhabitant(this)) ||(targetRoom.isInhabitant(this))) { this.setLocation(prevRoom); prevRoom.addInhabitant(this); targetRoom.delInhabitant(this); } if(mob.location()!=prevRoom) { if(mob.getVictim()==this) mob.makePeace(true); if(getVictim()==mob) makePeace(true); } } public synchronized void bestowBlessings(final MOB mob) { norecurse=true; try { if((!alreadyBlessed(mob))&&(numBlessings()>0)) { mob.location().show(this,mob,CMMsg.MSG_OK_VISUAL,L("You feel the presence of <S-NAME> in <T-NAME>.")); if((mob.charStats().getCurrentClass().baseClass().equals("Cleric")) ||(CMSecurity.isASysOp(mob))) { for(int b=0;b<numBlessings();b++) { final Ability Blessing=fetchBlessing(b); if(Blessing!=null) bestowBlessing(mob,Blessing); } } else { final int randNum=CMLib.dice().roll(1,numBlessings(),-1); final Ability Blessing=fetchBlessing(randNum); if((Blessing!=null)&&(!fetchBlessingCleric(randNum))) bestowBlessing(mob,Blessing); } } } catch(final Exception e) { Log.errOut("StdDeity",e); } norecurse=false; } public synchronized void bestowPowers(final MOB mob) { norecurse=true; try { if((!alreadyPowered(mob))&&(numPowers()>0)) { mob.location().show(this,mob,CMMsg.MSG_OK_VISUAL,L("You feel the power of <S-NAME> in <T-NAME>.")); final Ability Power=fetchPower(CMLib.dice().roll(1,numPowers(),-1)); if(Power!=null) bestowPower(mob,Power); } } catch(final Exception e) { Log.errOut("StdDeity",e); } norecurse=false; } public synchronized void bestowCurses(final MOB mob) { norecurse=true; try { if(numCurses()>0) { mob.location().show(this,mob,CMMsg.MSG_OK_VISUAL,L("You feel the wrath of <S-NAME> in <T-NAME>.")); if(mob.charStats().getCurrentClass().baseClass().equals("Cleric") ||(CMSecurity.isASysOp(mob))) { for(int b=0;b<numCurses();b++) { final Ability Curse=fetchCurse(b); if(Curse!=null) bestowCurse(mob,Curse); } } else { final int randNum=CMLib.dice().roll(1,numCurses(),-1); final Ability Curse=fetchCurse(randNum); if((Curse!=null)&&(!fetchBlessingCleric(randNum))) bestowCurse(mob,Curse); } } } catch(final Exception e) { Log.errOut("StdDeity",e); } norecurse=false; } public void removeBlessings(final MOB mob) { if((alreadyBlessed(mob))&&(mob.location()!=null)) { mob.location().show(this,mob,CMMsg.MSG_OK_VISUAL,L("<S-NAME> remove(s) <S-HIS-HER> blessings from <T-NAME>.")); for(int a=mob.numEffects()-1;a>=0;a--) // reverse, and personal { final Ability A=mob.fetchEffect(a); if((A!=null)&&(A.invoker()==this)) { A.unInvoke(); mob.delEffect(A); } } } } public void removePowers(final MOB mob) { if((alreadyPowered(mob))&&(mob.location()!=null)) { mob.location().show(this,mob,CMMsg.MSG_OK_VISUAL,L("<S-NAME> remove(s) <S-HIS-HER> powers from <T-NAME>.")); for(int a=mob.numAbilities()-1;a>=0;a--) { Ability A=mob.fetchAbility(a); if((A!=null)&&(!A.isSavable())) { mob.delAbility(A); A=mob.fetchEffect(A.ID()); if(A!=null) { A.unInvoke(); mob.delEffect(A); } } } } } public boolean alreadyBlessed(final MOB mob) { for(final Enumeration<Ability> a=mob.effects();a.hasMoreElements();) { final Ability A=a.nextElement(); if((A!=null)&&(A.invoker()==this)) return true; } return false; } public boolean alreadyPowered(final MOB mob) { if(numPowers()>0) for(int a=0;a<mob.numAbilities();a++) { final Ability A=mob.fetchAbility(a); if((A!=null)&&(!A.isSavable())) return true; } return false; } public boolean triggerCheck(final CMMsg msg, final List<DeityTrigger> V, final Map<String, boolean[]> trigParts, final Map<String, Long> trigTimes) { boolean recheck=false; for(int v=0;v<V.size();v++) { boolean yup=false; final DeityTrigger DT=V.get(v); if((msg.sourceMinor()==DT.triggerCode.getCMMsgCode()) ||(DT.triggerCode.getCMMsgCode()==-999)) { switch(DT.triggerCode) { case SAY: if((msg.sourceMessage()!=null)&&(msg.sourceMessage().toUpperCase().indexOf(DT.parm1)>0)) yup=true; break; case TIME: if((msg.source().location()!=null) &&(msg.source().location().getArea().getTimeObj().getHourOfDay()==CMath.s_int(DT.parm1))) yup=true; break; case RANDOM: if(CMLib.dice().rollPercentage()<=CMath.s_int(DT.parm1)) yup=true; break; case YOUSAY: if(v<=0) yup=true; else { final boolean[] checks=trigParts.get(msg.source().Name()); if((checks!=null)&&(checks[v-1])&&(!checks[v])) { yup=true; norecurse=true; CMLib.commands().postSay(msg.source(),null,CMStrings.capitalizeAndLower(DT.parm1)); norecurse=false; } else if((checks!=null)&&checks[v]) continue; } break; case ALLSAY: if(v<=0) yup=true; else { final boolean[] checks=trigParts.get(msg.source().Name()); final Room R=msg.source().location(); if((checks!=null)&&(checks[v-1])&&(!checks[v])&&(R!=null)) { yup=true; for(int m=0;m<R.numInhabitants();m++) { final MOB M=R.fetchInhabitant(m); if(M!=null) { norecurse=true; CMLib.commands().postSay(M,null,CMStrings.capitalizeAndLower(DT.parm1)); norecurse=false; } } } else if((checks!=null)&&checks[v]) continue; } break; case OTHERSAY: if(v<=0) yup=true; else { final boolean[] checks=trigParts.get(msg.source().Name()); final Room R=msg.source().location(); if((checks!=null)&&(checks[v-1])&&(!checks[v])&&(R!=null)) { yup=true; for(int m=0;m<R.numInhabitants();m++) { final MOB M=R.fetchInhabitant(m); if((M!=null)&&(M!=msg.source())) { norecurse=true; CMLib.commands().postSay(M,null,CMStrings.capitalizeAndLower(DT.parm1)); norecurse=false; } } } else if((checks!=null)&&checks[v]) continue; } break; case WAIT: { if(v<=0) yup=true; else { final boolean[] checks=trigParts.get(msg.source().Name()); if((checks!=null) &&(checks[v-1]) &&(!checks[v]) &&(trigTimes.get(msg.source().Name())!=null)) { boolean proceed=true; for(int t=v+1;t<checks.length;t++) { if(checks[t]) proceed=false; } if(proceed) { if(System.currentTimeMillis()>(trigTimes.get(msg.source().Name()).longValue()+(CMath.s_int(DT.parm1)*CMProps.getTickMillis()))) { yup=true; synchronized(waitingFor) { waitingFor.remove(msg.source()); } } else { synchronized(waitingFor) { waitingFor.add(msg.source()); } return false; } } } else if((checks!=null)&&(checks[v])) continue; } break; } case CHECK: if(CMLib.masking().maskCheck(DT.parm1,msg.source(),true)) yup=true; break; case PUTTHING: if((msg.target() instanceof Container) &&(msg.tool() instanceof Item) &&(CMLib.english().containsString(msg.tool().name(),DT.parm1)) &&(CMLib.english().containsString(msg.target().name(),DT.parm2))) yup=true; break; case BURNTHING: case READING: case DRINK: case EAT: if((msg.target()!=null) &&(DT.parm1.equals("0")||CMLib.english().containsString(msg.target().name(),DT.parm1))) yup=true; break; case INROOM: if(msg.source().location()!=null) { if(DT.parm1.equalsIgnoreCase("holy")||DT.parm1.equalsIgnoreCase("unholy")||DT.parm1.equalsIgnoreCase("balance")) yup=CMLib.law().getClericInfused(msg.source().location())==this; else if(msg.source().location().roomID().equalsIgnoreCase(DT.parm1)) yup=true; } break; case RIDING: if((msg.source().riding()!=null) &&(CMLib.english().containsString(msg.source().riding().name(),DT.parm1))) yup=true; break; case CAST: if((msg.tool()!=null) &&((msg.tool().ID().equalsIgnoreCase(DT.parm1)) ||(CMLib.english().containsString(msg.tool().name(),DT.parm1)))) yup=true; break; case EMOTE: if((msg.sourceMessage()!=null)&&(msg.sourceMessage().toUpperCase().indexOf(DT.parm1)>0)) yup=true; break; case PUTVALUE: if((msg.tool() instanceof Item) &&(((Item)msg.tool()).baseGoldValue()>=CMath.s_int(DT.parm1)) &&(msg.target() instanceof Container) &&(CMLib.english().containsString(msg.target().name(),DT.parm2))) yup=true; break; case PUTMATERIAL: if((msg.tool() instanceof Item) &&(((((Item)msg.tool()).material()&RawMaterial.RESOURCE_MASK)==CMath.s_int(DT.parm1)) ||((((Item)msg.tool()).material()&RawMaterial.MATERIAL_MASK)==CMath.s_int(DT.parm1))) &&(msg.target() instanceof Container) &&(CMLib.english().containsString(msg.target().name(),DT.parm2))) yup=true; break; case BURNMATERIAL: if((msg.target() instanceof Item) &&(((((Item)msg.target()).material()&RawMaterial.RESOURCE_MASK)==CMath.s_int(DT.parm1)) ||((((Item)msg.target()).material()&RawMaterial.MATERIAL_MASK)==CMath.s_int(DT.parm1)))) yup=true; break; case BURNVALUE: if((msg.target() instanceof Item) &&(((Item)msg.target()).baseGoldValue()>=CMath.s_int(DT.parm1))) yup=true; break; case SITTING: yup=CMLib.flags().isSitting(msg.source()); break; case STANDING: yup=(CMLib.flags().isStanding(msg.source())); break; case SLEEPING: yup=CMLib.flags().isSleeping(msg.source()); break; } } if((yup)||(DT.triggerCode.getCMMsgCode()==-999)) { boolean[] checks=trigParts.get(msg.source().Name()); if(yup) { recheck=true; trigTimes.remove(msg.source().Name()); trigTimes.put(msg.source().Name(),Long.valueOf(System.currentTimeMillis())); if((checks==null)||(checks.length!=V.size())) { checks=new boolean[V.size()]; trigParts.put(msg.source().Name(),checks); } } if(checks!=null) checks[v]=yup; } } return recheck; } @Override public void executeMsg(final Environmental myHost, final CMMsg msg) { super.executeMsg(myHost,msg); if(norecurse) return; if(msg.amITarget(this)) { switch(msg.targetMinor()) { case CMMsg.TYP_SERVE: msg.source().setWorshipCharID(name()); break; case CMMsg.TYP_REBUKE: if(msg.source().getWorshipCharID().equals(Name())) { msg.source().setWorshipCharID(""); removeBlessings(msg.source()); if(msg.source().charStats().getCurrentClass().baseClass().equals("Cleric")) { removePowers(msg.source()); msg.source().tell(L("You feel the wrath of @x1!",name())); if(!CMSecurity.isDisabled(CMSecurity.DisFlag.LEVELS)) msg.source().charStats().getCurrentClass().unLevel(msg.source()); } else { xpwrath=-CMLib.leveler().postExperience(msg.source(),null,null,-xpwrath,false); msg.source().tell(L("@x1 takes @x2 of experience from you.",name(),""+xpwrath)); } } break; } } else if(msg.source().getWorshipCharID().equals(name())) { if(numBlessings()>0) { List<DeityTrigger> V=worshipTriggers; if(msg.source().charStats().getCurrentClass().baseClass().equals("Cleric")) V=clericTriggers; if((V!=null)&&(V.size()>0)) { final boolean recheck=triggerCheck(msg,V,trigBlessingParts,trigBlessingTimes); if((recheck)&&(!norecurse)&&(!alreadyBlessed(msg.source()))) { final boolean[] checks=trigBlessingParts.get(msg.source().Name()); if((checks!=null)&&(checks.length==V.size())&&(checks.length>0)) { boolean rollingTruth=checks[0]; for(int v=1;v<V.size();v++) { final DeityTrigger DT=V.get(v); if(DT.previousConnect==RitualConnector.AND) rollingTruth=rollingTruth&&checks[v]; else rollingTruth=rollingTruth||checks[v]; } if(rollingTruth) bestowBlessings(msg.source()); } } } } if(numCurses()>0) { List<DeityTrigger> V=worshipCurseTriggers; if(msg.source().charStats().getCurrentClass().baseClass().equals("Cleric")) V=clericCurseTriggers; if((V!=null)&&(V.size()>0)) { final boolean recheck=triggerCheck(msg,V,trigCurseParts,trigCurseTimes); if((recheck)&&(!norecurse)) { final boolean[] checks=trigCurseParts.get(msg.source().Name()); if((checks!=null)&&(checks.length==V.size())&&(checks.length>0)) { boolean rollingTruth=checks[0]; for(int v=1;v<V.size();v++) { final DeityTrigger DT=V.get(v); if(DT.previousConnect==RitualConnector.AND) rollingTruth=rollingTruth&&checks[v]; else rollingTruth=rollingTruth||checks[v]; } if(rollingTruth) bestowCurses(msg.source()); } } } } if((numPowers()>0) &&(msg.source().charStats().getCurrentClass().baseClass().equals("Cleric") ||(CMSecurity.isASysOp(msg.source())))) { final List<DeityTrigger> V=clericPowerTriggers; if((V!=null)&&(V.size()>0)) { final boolean recheck=triggerCheck(msg,V,trigPowerParts,trigPowerTimes); if((recheck)&&(!norecurse)&&(!alreadyPowered(msg.source()))) { final boolean[] checks=trigPowerParts.get(msg.source().Name()); if((checks!=null)&&(checks.length==V.size())&&(checks.length>0)) { boolean rollingTruth=checks[0]; for(int v=1;v<V.size();v++) { final DeityTrigger DT=V.get(v); if(DT.previousConnect==RitualConnector.AND) rollingTruth=rollingTruth&&checks[v]; else rollingTruth=rollingTruth||checks[v]; } if(rollingTruth) bestowPowers(msg.source()); } } } } if((msg.source().charStats().getCurrentClass().baseClass().equals("Cleric") ||(CMSecurity.isASysOp(msg.source()))) &&(CMLib.law().getClericInfused(msg.source().location())==this)) { final List<DeityTrigger> V=serviceTriggers; if((V!=null)&&(V.size()>0)) { final boolean recheck=triggerCheck(msg,V,trigServiceParts,trigServiceTimes); if((recheck)&&(!norecurse)&&(!alreadyServiced(msg.source(),msg.source().location()))) { final boolean[] checks=trigServiceParts.get(msg.source().Name()); if((checks!=null)&&(checks.length==V.size())&&(checks.length>0)) { boolean rollingTruth=checks[0]; for(int v=1;v<V.size();v++) { final DeityTrigger DT=V.get(v); if(rollingTruth) startServiceIfNecessary(msg.source(),msg.source().location()); if(DT.previousConnect==RitualConnector.AND) rollingTruth=rollingTruth&&checks[v]; else rollingTruth=rollingTruth||checks[v]; } if(rollingTruth) finishService(msg.source(),msg.source().location()); } } } } } } protected void startServiceIfNecessary(final MOB mob, final Room room) { if((mob==null)||(room==null)) return; final List<MOB> parishaners=new ArrayList<MOB>(); synchronized(services) { for(final WorshipService w : services) { if(w.room==room) return; } final WorshipService service = new WorshipService(); service.room=room; service.parishaners = parishaners; service.startTime = System.currentTimeMillis(); service.cleric = mob; service.serviceCompleted = false; services.add(service); final Ability A=CMLib.law().getClericInfusion(room); if(A!=null) A.setAbilityCode(1); } Room R=null; MOB M=null; final TrackingLibrary.TrackingFlags flags=CMLib.tracking().newFlags(); final List<Room> V=CMLib.tracking().getRadiantRooms(room,flags,5+(mob.phyStats().level()/5)); for(int v=0;v<V.size();v++) { R=V.get(v); if(CMLib.law().getClericInfused(R)!=this) for(int m=0;m<R.numInhabitants();m++) { M=R.fetchInhabitant(m); if(M==null) continue; if(M.getWorshipCharID().equals(Name())) { if(!M.isMonster()) M.tell(L("Services for @x1 are now starting at @x2.",Name(),room.displayText(null))); else if(!CMLib.flags().isATrackingMonster(M)) { final Ability TRACKA=CMClass.getAbility("Skill_Track"); if(TRACKA!=null) { TRACKA.invoke(M,CMParms.parse("\""+CMLib.map().getExtendedRoomID(room)+"\""),room,true,0); parishaners.add(M); } } } } } } protected void undoService(final List<MOB> V) { MOB M=null; Ability A=null; for(int m=V.size()-1;m>=0;m--) { M=V.get(m); if(M==null) continue; A=M.fetchEffect("Skill_Track"); if(A!=null) A.unInvoke(); M.delEffect(A); CMLib.tracking().wanderAway(M,false,true); } } protected boolean alreadyServiced(final MOB mob, final Room room) { synchronized(services) { for(int d=services.size()-1;d>=0;d--) { final WorshipService service = services.get(d); if(System.currentTimeMillis()-service.startTime>(1000*60*30)) { undoService(service.parishaners); services.remove(d); final Ability A=CMLib.law().getClericInfusion(service.room); if(A!=null) A.setAbilityCode(0); } else if((service.room != null) &&(service.room.getArea()==room.getArea()) &&(service.serviceCompleted)) return true; } } return false; } public boolean finishService(final MOB mob, final Room room) { if((mob==null)||(room==null)) return false; MOB M=null; int totalLevels=0; WorshipService service = null; synchronized(services) { for(final WorshipService s : services) { if((s.room==room) && (s.cleric == mob)) service = s; } if(service == null) { for(final WorshipService s : services) { if(s.room==room) service = s; } } } if(service == null) return false; service.serviceCompleted = true; for(int m=0;m<room.numInhabitants();m++) { M=room.fetchInhabitant(m); if(M==null) continue; if(M.getWorshipCharID().equals(Name())) { if((!M.isMonster())&&(M!=mob)) CMLib.leveler().postExperience(M,null,null,50,false); totalLevels+=M.phyStats().level(); if(!M.isMonster()) totalLevels+=(M.phyStats().level()*2); final Ability A=M.fetchEffect("Skill_Convert"); if(A!=null) A.makeLongLasting(); } } undoService(service.parishaners); final int exp=(int)Math.round(CMath.div(totalLevels,mob.phyStats().level())*10.0); CMLib.leveler().postExperience(mob,null,null,exp,false); trigServiceParts.remove(mob.Name()); trigServiceTimes.remove(mob.Name()); return true; } public boolean cancelService(final WorshipService service) { if(service == null) return false; final Room room = service.room; final MOB mob = service.cleric; MOB M=null; for(int m=0;m<room.numInhabitants();m++) { M=room.fetchInhabitant(m); if(M==null) continue; if(M.getWorshipCharID().equals(Name())) { final Ability A=M.fetchEffect("Skill_Convert"); if(A!=null) A.unInvoke(); } } room.showHappens(CMMsg.MASK_ALWAYS, L("The service conducted by @x1 has been cancelled.",mob.Name())); if(mob.location()!=room) mob.tell(L("Your service has been cancelled.")); undoService(service.parishaners); synchronized(services) { services.remove(service); final Ability A=CMLib.law().getClericInfusion(service.room); if(A!=null) A.setAbilityCode(0); } trigServiceParts.remove(mob.Name()); trigServiceTimes.remove(mob.Name()); return true; } @Override public boolean tick(final Tickable ticking, final int tickID) { if(!super.tick(ticking,tickID)) return false; if((tickID==Tickable.TICKID_MOB) &&((--rebukeCheckDown)<0)) { rebukeCheckDown=10; for(final Enumeration<MOB> p=CMLib.players().players();p.hasMoreElements();) { final MOB M=p.nextElement(); if((lastBlackmark>0) &&(blacklist!=null) &&(blacklist!=M) &&((System.currentTimeMillis()-lastBlackmark)<120000)) continue; if((!M.isMonster())&&(M.getWorshipCharID().equals(name()))&&(CMLib.flags().isInTheGame(M,true))) { if(M.charStats().getCurrentClass().baseClass().equalsIgnoreCase("Cleric")) { if(!CMLib.masking().maskCheck(getClericRequirements(),M,true)) { if((blacklist==M)&&((++blackmarks)>30)) { final CMMsg msg=CMClass.getMsg(M,this,null,CMMsg.MSG_REBUKE,L("<S-NAME> <S-HAS-HAVE> been rebuked by <T-NAME>!!")); if((M.location()!=null)&&(M.okMessage(M,msg))) M.location().send(M,msg); blackmarks=0; blacklist=null; lastBlackmark=0; } else { if(blacklist!=M) blackmarks=0; blacklist=M; blackmarks++; lastBlackmark=System.currentTimeMillis(); if((blackmarks%5)==0) M.tell(L("You feel dirtied by the disappointment of @x1.",name())); } } else if(blacklist==M) { blackmarks=0; blacklist=null; lastBlackmark=0; } } else if(!CMLib.masking().maskCheck(getWorshipRequirements(),M,true)) { if((blacklist==M)&&((++blackmarks)>30)) { final CMMsg msg=CMClass.getMsg(M,this,null,CMMsg.MSG_REBUKE,L("<S-NAME> <S-HAS-HAVE> been rebuked by <T-NAME>!!")); if((M.location()!=null)&&(M.okMessage(M,msg))) M.location().send(M,msg); } else { if(blacklist!=M) blackmarks=0; blacklist=M; blackmarks++; lastBlackmark=System.currentTimeMillis(); if(blackmarks==1) M.tell(L("Worshipper, you have disappointed @x1. Make amends or face my wrath!",name())); } } else if(blacklist==M) { blackmarks=0; blacklist=null; lastBlackmark=0; } } else if(blacklist==M) { blackmarks=0; blacklist=null; lastBlackmark=0; } } final long curTime=System.currentTimeMillis()-60000; Long L=null; for(final String key : trigBlessingTimes.keySet()) { L=trigBlessingTimes.get(key); if((L!=null)&&(L.longValue()<curTime)) { trigBlessingTimes.remove(key); trigBlessingParts.remove(key); } } for(final String key : trigPowerTimes.keySet()) { L=trigPowerTimes.get(key); if((L!=null)&&(L.longValue()<curTime)) { trigPowerTimes.remove(key); trigPowerParts.remove(key); } } for(final String key : trigCurseTimes.keySet()) { L=trigCurseTimes.get(key); if((L!=null)&&(L.longValue()<curTime)) { trigCurseTimes.remove(key); trigCurseParts.remove(key); } } for(final String key : trigServiceTimes.keySet()) { L=trigServiceTimes.get(key); if((L!=null)&&(L.longValue()<curTime)) { LinkedList<WorshipService> delThese = null; synchronized(services) { for(final WorshipService service : services) { if((service.cleric!=null) &&(service.cleric.Name().equalsIgnoreCase(key)) &&(!service.serviceCompleted)) { if(delThese == null) delThese = new LinkedList<WorshipService>(); delThese.add(service); } } } if(delThese != null) { for(final WorshipService w : delThese) cancelService(w); } } } } if(waitingFor.size()>0) { final List<MOB> executeMOBList; synchronized(waitingFor) { if(waitingFor.size()>0) { executeMOBList=new ArrayList<MOB>(waitingFor); waitingFor.clear(); } else executeMOBList=null; } if(executeMOBList != null) { for (final MOB M : executeMOBList) { try { executeMsg(this,CMClass.getMsg(M,null,null,CMMsg.MSG_OK_VISUAL,null)); } catch(final Exception e) { } } } } return true; } @Override public void addBlessing(final Ability to, final boolean clericOnly) { if(to==null) return; for(int a=0;a<numBlessings();a++) { final Ability A=fetchBlessing(a); if((A!=null)&&(A.ID().equals(to.ID()))) return; } blessings.add(new DeityPower(to,clericOnly)); } @Override public void delBlessing(final Ability to) { if(blessings.size()==0) return; for(final DeityPower P : blessings) { if(P.power==to) blessings.remove(P); } } @Override public int numBlessings() { return blessings.size(); } @Override public Ability fetchBlessing(final int index) { try { return blessings.get(index).power; } catch(final java.lang.ArrayIndexOutOfBoundsException x) { } return null; } @Override public boolean fetchBlessingCleric(final int index) { try { return blessings.get(index).clericOnly; } catch(final java.lang.ArrayIndexOutOfBoundsException x) { } return false; } @Override public boolean fetchBlessingCleric(final String ID) { for(int a=0;a<numBlessings();a++) { final Ability A=fetchBlessing(a); if((A!=null) &&((A.ID().equalsIgnoreCase(ID))||(A.Name().equalsIgnoreCase(ID)))) return fetchBlessingCleric(a); } return false; } @Override public Ability fetchBlessing(final String ID) { for(int a=0;a<numBlessings();a++) { final Ability A=fetchBlessing(a); if((A!=null) &&((A.ID().equalsIgnoreCase(ID))||(A.Name().equalsIgnoreCase(ID)))) return A; } return (Ability)CMLib.english().fetchEnvironmental(new ConvertingList<DeityPower,Ability>(blessings,new Converter<DeityPower,Ability>() { @Override public Ability convert(final DeityPower obj) { return obj.power; } }),ID,false); } protected void parseTriggers(final List<DeityTrigger> putHere, String trigger) { putHere.clear(); trigger=trigger.toUpperCase().trim(); RitualConnector previousConnector=RitualConnector.AND; if(trigger.equals("-")) return; while(trigger.length()>0) { final int div1=trigger.indexOf('&'); final int div2=trigger.indexOf('|'); int div=div1; if((div2>=0)&&((div<0)||(div2<div))) div=div2; String trig=null; if(div<0) { trig=trigger; trigger=""; } else { trig=trigger.substring(0,div).trim(); trigger=trigger.substring(div+1); } if(trig.length()>0) { final Vector<String> V=CMParms.parse(trig); if(V.size()>1) { final String cmd=V.firstElement(); DeityTrigger DT=new DeityTrigger(); RitualTrigger T = (RitualTrigger)CMath.s_valueOf(RitualTrigger.class, cmd); if(T==null) { for(final RitualTrigger RT : RitualTrigger.values()) { if(RT.getShortName().equals(cmd)) { T=RT; break; } } } if(T==null) { for(final RitualTrigger RT : RitualTrigger.values()) { if(RT.name().startsWith(cmd)) { T=RT; break; } } } DT.previousConnect=previousConnector; if(T==null) { Log.errOut("StdDeity",Name()+"- Illegal trigger: '"+cmd+"','"+trig+"'"); break; } else switch(T) { case SAY: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case TIME: { DT.triggerCode=T; DT.parm1=""+CMath.s_int(CMParms.combine(V,1)); } break; case WAIT: { DT.triggerCode=T; DT.parm1=""+CMath.s_int(CMParms.combine(V,1)); } break; case YOUSAY: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case OTHERSAY: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case ALLSAY: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case PUTTHING: { DT.triggerCode=T; if(V.size()<3) { Log.errOut("StdDeity",Name()+"- Illegal trigger: "+trig); DT=null; break; } DT.parm1=CMParms.combine(V,1,V.size()-2); DT.parm2=V.lastElement(); } break; case BURNTHING: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case PUTVALUE: { DT.triggerCode=T; if(V.size()<3) { Log.errOut("StdDeity",Name()+"- Illegal trigger: "+trig); DT=null; break; } DT.parm1=""+CMath.s_int(V.elementAt(1)); DT.parm2=CMParms.combine(V,2); } break; case BURNVALUE: { DT.triggerCode=T; if(V.size()<3) { Log.errOut("StdDeity",Name()+"- Illegal trigger: "+trig); DT=null; break; } DT.parm1=""+CMath.s_int(CMParms.combine(V,1)); } break; case BURNMATERIAL: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); final int cd = RawMaterial.CODES.FIND_StartsWith(DT.parm1); boolean found=cd>=0; if(found) DT.parm1=""+cd; else { final RawMaterial.Material m=RawMaterial.Material.startsWith(DT.parm1); if(m!=null) { DT.parm1=""+m.mask(); found=true; } } if(!found) { Log.errOut("StdDeity",Name()+"- Unknown material: "+trig); DT=null; break; } } break; case PUTMATERIAL: { DT.triggerCode=T; if(V.size()<3) { Log.errOut("StdDeity",Name()+"- Illegal trigger: "+trig); DT=null; break; } DT.parm1=V.elementAt(1); DT.parm2=CMParms.combine(V,2); final int cd = RawMaterial.CODES.FIND_StartsWith(DT.parm1); boolean found=cd>=0; if(found) DT.parm1=""+cd; else if(!found) { final RawMaterial.Material m=RawMaterial.Material.startsWith(DT.parm1); if(m!=null) { DT.parm1=""+m.mask(); found=true; } } if(!found) { Log.errOut("StdDeity",Name()+"- Unknown material: "+trig); DT=null; break; } } break; case EAT: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case READING: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case RANDOM: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case CHECK: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case DRINK: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case INROOM: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case RIDING: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case CAST: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); if(CMClass.findAbility(DT.parm1)==null) { Log.errOut("StdDeity",Name()+"- Illegal SPELL in: "+trig); DT=null; break; } } break; case EMOTE: { DT.triggerCode=T; DT.parm1=CMParms.combine(V,1); } break; case SITTING: { DT.triggerCode=T; } break; case STANDING: { DT.triggerCode=T; } break; case SLEEPING: { DT.triggerCode=T; } break; default: { Log.errOut("StdDeity",Name()+"- Illegal trigger: '"+cmd+"','"+trig+"'"); DT=null; break; } } if(DT==null) break; putHere.add(DT); } else { Log.errOut("StdDeity",Name()+"- Illegal trigger (need more parameters): "+trig); break; } } if(div==div1) previousConnector=RitualConnector.AND; else previousConnector=RitualConnector.OR; } } protected static class DeityTrigger { public RitualTrigger triggerCode=RitualTrigger.SAY; public RitualConnector previousConnect=RitualConnector.AND; public String parm1=null; public String parm2=null; } /** Manipulation of curse objects, which includes spells, traits, skills, etc.*/ @Override public void addCurse(final Ability to, final boolean clericOnly) { if(to==null) return; for(int a=0;a<numCurses();a++) { final Ability A=fetchCurse(a); if((A!=null)&&(A.ID().equals(to.ID()))) return; } curses.add(new DeityPower(to,clericOnly)); } @Override public void delCurse(final Ability to) { if((curses.size()==0)||(to==null)) return; for(int a=numCurses()-1;a>=0;a--) { final Ability A=fetchCurse(a); if(A==to) curses.remove(a); } } @Override public int numCurses() { return curses.size(); } @Override public Ability fetchCurse(final int index) { try { return curses.get(index).power; } catch(final java.lang.ArrayIndexOutOfBoundsException x) { } return null; } @Override public Ability fetchCurse(final String ID) { for(int a=0;a<numCurses();a++) { final Ability A=fetchCurse(a); if((A!=null)&&((A.ID().equalsIgnoreCase(ID))||(A.Name().equalsIgnoreCase(ID)))) return A; } return (Ability)CMLib.english().fetchEnvironmental(new ConvertingList<DeityPower,Ability>(curses,new Converter<DeityPower,Ability>() { @Override public Ability convert(final DeityPower obj) { return obj.power; } }),ID,false); } @Override public boolean fetchCurseCleric(final int index) { try { return curses.get(index).clericOnly; } catch(final java.lang.ArrayIndexOutOfBoundsException x) { } return false; } @Override public boolean fetchCurseCleric(final String ID) { for(int a=0;a<numCurses();a++) { final Ability A=fetchCurse(a); if((A!=null)&&((A.ID().equalsIgnoreCase(ID))||(A.Name().equalsIgnoreCase(ID)))) return fetchCurseCleric(a); } return false; } @Override public String getClericSin() { return clericSin; } @Override public void setClericSin(final String ritual) { clericSin=ritual; parseTriggers(clericCurseTriggers,ritual); } @Override public String getClericSinDesc() { if(numCurses()>0) return L("The curses of @x1 are placed upon @x2 clerics whenever the cleric does the following: @x3.",name(),charStats().hisher(),getTriggerDesc(clericCurseTriggers)); return ""; } @Override public String getWorshipSin() { return worshipSin; } @Override public void setWorshipSin(final String ritual) { worshipSin=ritual; parseTriggers(worshipCurseTriggers,ritual); } @Override public String getWorshipSinDesc() { if(numCurses()>0) return L("The curses of @x1 are placed upon @x2 worshippers whenever the worshipper does the following: @x3.",name(),charStats().hisher(),getTriggerDesc(worshipCurseTriggers)); return ""; } /** Manipulation of granted clerical powers, which includes spells, traits, skills, etc.*/ /** Make sure that none of these can really be qualified for by the cleric!*/ /** Manipulation of curse objects, which includes spells, traits, skills, etc.*/ @Override public void addPower(final Ability to) { if(to==null) return; for(int a=0;a<numPowers();a++) { final Ability A=fetchPower(a); if((A!=null)&&(A.ID().equals(to.ID()))) return; } powers.add(to); } @Override public void delPower(final Ability to) { powers.remove(to); } @Override public int numPowers() { return powers.size(); } @Override public Ability fetchPower(final int index) { try { return powers.get(index); } catch(final java.lang.ArrayIndexOutOfBoundsException x) { } return null; } @Override public Ability fetchPower(final String ID) { for(int a=0;a<numPowers();a++) { final Ability A=fetchPower(a); if((A!=null)&&((A.ID().equalsIgnoreCase(ID))||(A.Name().equalsIgnoreCase(ID)))) return A; } return (Ability)CMLib.english().fetchEnvironmental(powers,ID,false); } @Override public String getClericPowerup() { return clericPowerup; } @Override public void setClericPowerup(final String ritual) { clericPowerup=ritual; parseTriggers(clericPowerTriggers,ritual); } @Override public String getClericPowerupDesc() { if(numPowers()>0) return L("Special powers of @x1 are placed upon @x2 clerics whenever the cleric does the following: @x3.",name(),charStats().hisher(),getTriggerDesc(clericPowerTriggers)); return ""; } }