package com.planet_ink.coffee_mud.Common; 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.core.exceptions.*; 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.*; import com.planet_ink.coffee_mud.Libraries.interfaces.XMLLibrary.XMLTag; 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.*; import org.mozilla.javascript.Context; import org.mozilla.javascript.ScriptableObject; /* Copyright 2003-2016 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. */ @SuppressWarnings({"unchecked","rawtypes"}) public class DefaultQuest implements Quest, Tickable, CMObject { @Override public String ID() { return "DefaultQuest"; } protected String name = ""; protected String author = ""; protected String displayName = ""; protected String startDate = ""; protected int duration = 450;// about // 30 // minutes protected String rawScriptParameter = ""; protected boolean durable = false; protected int minWait = -1; protected int minPlayers = -1; protected String playerMask = ""; protected int runLevel = -1; protected int maxWait = -1; protected int waitRemaining = -1; protected int ticksRemaining = -1; protected long lastStartDateTime = System.currentTimeMillis(); private boolean stoppingQuest = false; protected int spawn = SPAWN_NO; private QuestState questState = new QuestState(); private boolean copy = false; private boolean suspended = false; public DVector internalFiles = null; private int[] resetData = null; protected final Map<String,Long> stepEllapsedTimes = new Hashtable<String,Long>(); protected final Map<String,Long> winners = new CaselessTreeMap<Long>(); // the unique name of the quest @Override public String name() { return name; } @Override public void setName(String newName) { name = newName; } // the author of the quest @Override public String author() { return author; } @Override public void setAuthor(String newName) { author = newName; } // the display name of the quest @Override public String displayName() { return displayName; } @Override public void setDisplayName(String newName) { displayName = newName; } @Override public CMObject copyOf() { try { final Object O=this.clone(); return (CMObject)O; } catch(final CloneNotSupportedException e) { return newInstance(); } } @Override public boolean suspended() { return suspended; } @Override public void setSuspended(boolean truefalse) { suspended = truefalse; } @Override public CMObject newInstance() { try { return getClass().newInstance(); } catch (final Exception e) { return new DefaultQuest(); } } @Override public void initializeClass() { } @Override public Object getDesignatedObject(String named) { int code=-1; for(int i=0;i<QCODES.length;i++) if(named.equalsIgnoreCase(QCODES[i])) { code=i; break;} switch(code) { case 0: return ID(); case 1: return name(); case 2: return "" + duration(); case 3: return "" + minWait(); case 4: return "" + minPlayers(); case 5: return "" + playerMask(); case 6: return "" + runLevel(); case 7: return "" + startDate(); case 8: return "" + startDate(); case 9: return "" + waitInterval(); case 10: return SPAWN_DESCS[getSpawn()]; case 11: return displayName(); case 12: break; // instructions should fall through case 13: return Boolean.toString(durable); case 14: return "" + author(); } return questState.getStat(named); } @Override public void internalQuestDelete() { if(isCopy()) return; if((internalFiles!=null)&&(internalFiles.size()>0)) { for(int i=0;i<internalFiles.size();i++) { final String filename=((String)internalFiles.elementAt(i,1)).toUpperCase(); final Vector<String> delThese=new Vector<String>(); boolean foundKey=false; for(final Iterator<String> k=Resources.findResourceKeys(filename);k.hasNext();) { final String key=k.next(); if(key.startsWith("PARSEDPRG: ")&&(key.toUpperCase().endsWith(filename))) { foundKey = true; delThese.addElement(key); } } if(foundKey) { for(int d=0;d<delThese.size();d++) Resources.removeResource(delThese.elementAt(d)); } } internalFiles.clear(); internalFiles=null; } } // the unique name of the quest @Override public String startDate() { return startDate; } @Override public void setStartDate(String newDate) { final int x=newDate.indexOf('-'); if((x>0) &&(CMath.isMathExpression(newDate.substring(0,x))) &&(CMath.isMathExpression(newDate.substring(x+1)))) startDate=newDate; } @Override public void setStartMudDate(String newDate) { setStartDate(newDate); if(startDate.equals(newDate)) startDate="MUDDAY "+startDate; } // the duration, in ticks @Override public int duration() { return duration; } @Override public void setDuration(int newTicks) { duration = newTicks; } @Override public void setCopy(boolean truefalse) { copy = truefalse; } @Override public boolean isCopy() { return copy; } @Override public void setSpawn(int spawnFlag) { spawn = (spawnFlag < 0) ? 0 : spawnFlag; } @Override public int getSpawn() { return spawn; } @Override public int minPlayers() { return minPlayers; } @Override public void setMinPlayers(int players) { minPlayers = players; } @Override public int runLevel() { return runLevel; } @Override public void setRunLevel(int level) { runLevel = level; } @Override public String playerMask() { return playerMask; } @Override public void setPlayerMask(String mask) { playerMask = mask; } // the rest of the script. This may be semicolon-separated instructions, // or a LOAD command followed by the quest script path. @Override public boolean setScript(String parm, boolean showErrors) { rawScriptParameter=parm; name=""; author=""; displayName=""; startDate=""; duration=-1; minWait=-1; maxWait=-1; minPlayers=-1; spawn=SPAWN_NO; playerMask=""; runLevel=-1; internalFiles=null; durable=false; final Vector questScripts=parseLoadScripts(parm,new Vector(),new Vector(),showErrors); if(questScripts.size()==0) return false; setVars(questScripts,0); if(isCopy()) spawn=SPAWN_NO; return true; } @Override public String script() { return rawScriptParameter; } @Override public void autostartup() { if(!resetWaitRemaining(0)) CMLib.threads().deleteTick(this,Tickable.TICKID_QUEST); else if(!running()) CMLib.threads().startTickDown(this,Tickable.TICKID_QUEST,1); } @Override public void setVars(List<?> script, int startAtLine) { List<String> parsedLine=null; String var=null; String val=null; final List<List<String>> setScripts=CMLib.quests().parseQuestCommandLines(script,"SET",startAtLine); for(int v=0;v<setScripts.size();v++) { parsedLine=setScripts.get(v); if(parsedLine.size()>1) { var=parsedLine.get(1).toUpperCase(); val=CMParms.combine(parsedLine,2); if(isStat(var)) setStat(var,val); } } } @Override public StringBuffer getResourceFileData(String named, boolean showErrors) { int index=-1; if(internalFiles!=null) { index=internalFiles.indexOf(named.toUpperCase().trim()); if(index>=0) return (StringBuffer)internalFiles.elementAt(index,2); } final StringBuffer buf=new CMFile(Resources.makeFileResourceName(named),null,showErrors?CMFile.FLAG_LOGERRORS:0).text(); return buf; } private void questifyScriptableBehavs(PhysicalAgent E) { if(E==null) return; Behavior B=null; for(final Enumeration<Behavior> e=E.behaviors();e.hasMoreElements();) { B=e.nextElement(); if(B instanceof ScriptingEngine) ((ScriptingEngine)B).registerDefaultQuest(this.name()); } } private Enumeration<Room> getAppropriateRoomSet(QuestState q) { if(q.roomGroup!=null) return new IteratorEnumeration(q.roomGroup.iterator()); else if(q.area!=null) return q.area.getMetroMap(); return CMLib.map().rooms(); } private final Iterable<Room> buildAppropriateRoomIterable(final QuestState q, final Iterable useThese) { final Enumeration<Room> e; if(useThese!=null) e=new IteratorEnumeration<Room>(useThese.iterator()); else if(q.area!=null) e=q.area.getMetroMap(); else e=CMLib.map().rooms(); final LinkedList<Room> list=new LinkedList<Room>(); for(;e.hasMoreElements();) list.add(e.nextElement()); return list; } private List sortSelect(Environmental E, String str, List choices, List choices0, List choices1, List choices2, List choices3) { final String mname=E.name().toUpperCase(); final String mdisp=E.displayText().toUpperCase(); final String mdesc=E.description().toUpperCase(); if(str.equalsIgnoreCase("any")) { choices=choices0; choices0.add(E); } else if(mname.equalsIgnoreCase(str)) { choices=choices0; choices0.add(E); } else if(CMLib.english().containsString(mname,str)) { if((choices==null)||(choices==choices2)||(choices==choices3)) choices=choices1; choices1.add(E); } else if(CMLib.english().containsString(mdisp,str)) { if((choices==null)||(choices==choices3)) choices=choices2; choices2.add(E); } else if(CMLib.english().containsString(mdesc,str)) { if(choices==null) choices=choices3; choices3.add(E); } return choices; } private TimeClock getMysteryTimeNowFromState() { TimeClock NOW=null; if(questState.mysteryData==null) return (TimeClock)CMLib.time().globalClock().copyOf(); if((questState.mysteryData.whereAt!=null)&&(questState.mysteryData.whereAt.getArea()!=null)) NOW=(TimeClock)questState.mysteryData.whereAt.getArea().getTimeObj().copyOf(); else if((questState.mysteryData.whereHappened!=null)&&(questState.mysteryData.whereHappened.getArea()!=null)) NOW=(TimeClock)questState.mysteryData.whereHappened.getArea().getTimeObj().copyOf(); else if((questState.room!=null)&&(questState.room.getArea()!=null)) NOW=(TimeClock)questState.room.getArea().getTimeObj().copyOf(); else if(questState.area!=null) NOW=(TimeClock)questState.area.getTimeObj().copyOf(); else NOW=(TimeClock)CMLib.time().globalClock().copyOf(); return NOW; } public void parseQuestScriptWArgs(Vector script, List args) { if(args==null) args=new Vector(); if(args.size()==0) parseQuestScript(script, args, -1); else { final Vector allArgs=new Vector(); for(int i=0;i<args.size();i++) { final Object O=args.get(i); if(O instanceof List) { final List V=(List)O; if(allArgs.size()==0) { for(int v=0;v<V.size();v++) allArgs.addElement(new XVector(V.get(v))); } else { final List allArgsCopy=(List)allArgs.clone(); allArgs.clear(); for(int aa=0;aa<allArgsCopy.size();aa++) { final List argSet=(List)allArgsCopy.get(aa); for(int v=0;v<V.size();v++) { final List V2=new XVector(argSet); V2.add(V.get(v)); allArgs.addElement(V2); } } } } else if(allArgs.size()==0) allArgs.addElement(new XVector(O)); else for(int aa=0;aa<allArgs.size();aa++) ((List)allArgs.elementAt(aa)).add(O); } for(int a=0;a<allArgs.size();a++) parseQuestScript(script, (List)allArgs.elementAt(a),-1); } } protected void errorOccurred(QuestState q, boolean quietFlag, String msg) { if(!quietFlag) Log.errOut("Quest",msg); q.error=true; } private void sizeDownTo(List V, int num) { if(num<0) return; if(num==0) V.clear(); else while(V.size()>num) V.remove(CMLib.dice().roll(1,V.size(),-1)); } protected void filterOutThoseInUse(final List<? extends Environmental> choices, final String choicesStr, final QuestState q, final boolean isQuiet, final boolean reselect) { if((choices!=null)&&(choices.size()>0)) { Set<String> inUseByWhom=new TreeSet<String>(); for(int c=choices.size()-1;c>=0;c--) { if((!reselect)||(!q.reselectable.contains(choices.get(c)))) { final Quest Q=CMLib.quests().objectInUse(choices.get(c)); if(Q!=null) { choices.remove(c); inUseByWhom.add(Q.name()); } } } if((choices.size()==0)&&(!isQuiet)) errorOccurred(q,isQuiet,"Quest '"+name()+"', all choices were taken: '"+choicesStr+"' by: "+CMParms.toListString(inUseByWhom)+"."); } } public void parseQuestScript(Vector script, List args, int startLine) { final Vector<String> finalScript=new Vector<String>(); for(int v=0;v<script.size();v++) { if(script.elementAt(v) instanceof String) finalScript.addElement((String)script.elementAt(v)); else if(script.elementAt(v) instanceof List) { final int vs=v; while((v<script.size())&&(script.elementAt(v) instanceof List)) v++; final int rnum=vs+CMLib.dice().roll(1,v-vs,-1); if(rnum<script.size()) { final List V=(List)script.elementAt(rnum); for(int v2=0;v2<V.size();v2++) { if(V.get(v2) instanceof String) finalScript.addElement((String)V.get(v2)); } } } } script=finalScript; final QuestState q=questState; int vStart=startLine; if(vStart<0) vStart=0; q.done=false; if(vStart>=script.size()) return; q.startLine=vStart; for(int v=vStart;v<script.size();v++) { if(startLine>=0) q.lastLine=v; final String s=modifyStringFromArgs((String)script.elementAt(v),args); final Vector<String> p=CMParms.parse(s); boolean isQuiet=q.beQuiet; if(p.size()>0) { String cmd=p.elementAt(0).toUpperCase(); if(cmd.equals("<SCRIPT>")) { final StringBuffer jscript=new StringBuffer(""); while(((++v)<script.size()) &&(!((String)script.elementAt(v)).trim().toUpperCase().startsWith("</SCRIPT>"))) jscript.append(((String)script.elementAt(v))+"\n"); if(v>=script.size()) { errorOccurred(q,false,"Quest '"+name()+"', <SCRIPT> command without </SCRIPT> found."); break; } if(!CMSecurity.isApprovedJScript(jscript)) { errorOccurred(q,false,"Quest '"+name()+"', <SCRIPT> not approved. Use MODIFY JSCRIPT to approve."); break; } final Context cx = Context.enter(); try { final JScriptQuest scope = new JScriptQuest(this,q); cx.initStandardObjects(scope); scope.defineFunctionProperties(JScriptQuest.functions, JScriptQuest.class, ScriptableObject.DONTENUM); cx.evaluateString(scope, jscript.toString(),"<cmd>", 1, null); } catch(final Exception e) { errorOccurred(q,false,"Quest '"+name()+"', JScript q.error: "+e.getMessage()+"."); Context.exit(); break; } Context.exit(); continue; } if(cmd.equals("QUIET")) { if(p.size()<2) { q.beQuiet=true; continue; } isQuiet=true; p.removeElementAt(0); cmd=p.elementAt(0).toUpperCase(); } if(cmd.equals("STEP")) { q.autoStepAfterDuration=false; if((p.size()>1)&&(p.elementAt(1).equalsIgnoreCase("BREAK"))) { q.lastLine=script.size(); q.done=true; } else if((p.size()>1)&&(p.elementAt(1).equalsIgnoreCase("BACK"))) { if(startLine>=0) q.lastLine=q.startLine; } else if((p.size()>1)&&(p.elementAt(1).equalsIgnoreCase("AUTO"))) { if(startLine>=0) q.lastLine=v+1; q.autoStepAfterDuration=true; } else if(startLine>=0) q.lastLine=v+1; return; } if(cmd.equals("RESET")) { if(q.room!=null) CMLib.map().resetRoom(q.room, true); else if(q.roomGroup!=null) { for(int r=0;r<q.roomGroup.size();r++) CMLib.map().resetRoom(q.roomGroup.get(r), true); } else if(q.area!=null) CMLib.map().resetArea(q.area); else { errorOccurred(q,false,"Quest '"+name()+"', no resettable room, roomgroup, area, or areagroup set."); break; } } else if(cmd.equals("SET")) { if(p.size()<2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', unfound variable on set."); break; } cmd=p.elementAt(1).toUpperCase(); if(cmd.equals("AREA")) { if(p.size()<3) { q.area=null; continue; } try { q.area = (Area) getObjectIfSpecified(p, args, 2, 0); q.envObject = q.area; continue; } catch(final CMException ex) { q.area=null; } final Vector<String> names=new Vector<String>(); final Vector<Area> areas=new Vector<Area>(); if((p.size()>3)&&(p.elementAt(2).equalsIgnoreCase("any"))) { for(int ip=3;ip<p.size();ip++) names.addElement(p.elementAt(ip)); } else names.addElement(CMParms.combine(p,2)); for(int n=0;n<names.size();n++) { final String areaName=names.elementAt(n); final int oldSize=areas.size(); if(areaName.equalsIgnoreCase("any")) areas.addElement(CMLib.map().getRandomArea()); if(oldSize==areas.size()) { for (final Enumeration e = CMLib.map().areas(); e.hasMoreElements(); ) { final Area A2 = (Area) e.nextElement(); if (A2.Name().equalsIgnoreCase(areaName)) { areas.addElement(A2); break; } } } if(oldSize==areas.size()) { for(final Enumeration e=CMLib.map().areas();e.hasMoreElements();) { final Area A2=(Area)e.nextElement(); if(CMLib.english().containsString(A2.Name(),areaName)) { areas.addElement(A2); break; } } } } if(areas.size()>0) q.area=areas.elementAt(CMLib.dice().roll(1,areas.size(),-1)); if(q.area==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown area '"+CMParms.combine(p,2)+"'."); break; } } else if(cmd.equals("AREAGROUP")) { q.area=null; q.roomGroup=null; if(p.size()<3) continue; final Vector<String> names=new Vector<String>(); final Vector<Area> areas=new Vector<Area>(); for(int ip=2;ip<p.size();ip++) names.addElement(p.elementAt(ip)); for(int n=0;n<names.size();n++) { final String areaName=names.elementAt(n); final int oldSize=areas.size(); if(areaName.equalsIgnoreCase("any")) areas.addElement(CMLib.map().getRandomArea()); final boolean addAll=areaName.equalsIgnoreCase("all"); if(oldSize==areas.size()) { if(addAll) { for (final Enumeration<Area> e = CMLib.map().areas(); e.hasMoreElements(); ) { final Area A2=e.nextElement(); if(!areas.contains(A2)) areas.add(A2); } } else { final Area A2=CMLib.map().findArea(areaName); if((A2!=null)&&(!areas.contains(A2))) areas.add(A2); } } } if(areas.size()>0) { q.roomGroup=new Vector<Room>(); Room R=null; for (final Area A : areas) { for(final Enumeration<Room> e2=A.getMetroMap();e2.hasMoreElements();) { R=e2.nextElement(); if(!q.roomGroup.contains(R)) q.roomGroup.add(R); } } q.envObject=q.roomGroup; } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown areas '"+CMParms.combine(p,2)+"'."); break; } } else if(cmd.equals("MOBTYPE")) { boolean reselect=false; if((p.size()>2)&&(p.elementAt(2).equalsIgnoreCase("reselect"))) { p.removeElementAt(2); reselect=true; } if(p.size()<3) { q.mob=null; continue; } try { q.mob=(MOB)getObjectIfSpecified(p,args,2,0); } catch(final CMException ex) { q.mob=null; final List<MOB> choices=new Vector<MOB>(); final Vector<String> mobTypes=CMParms.parse(CMParms.combine(p,2).toUpperCase()); for(int t=0;t<mobTypes.size();t++) { final String mobType=mobTypes.elementAt(t); if(mobType.startsWith("-")) continue; if(q.mobGroup==null) { try { for(final Enumeration e=getAppropriateRoomSet(q);e.hasMoreElements();) { final Room R2=(Room)e.nextElement(); for(int i=0;i<R2.numInhabitants();i++) { final MOB M2=R2.fetchInhabitant(i); if((M2!=null) &&(M2.isMonster()) &&((M2.amUltimatelyFollowing()==null)||(M2.amUltimatelyFollowing().isMonster()))) { if(mobType.equalsIgnoreCase("any")) choices.add(M2); else if((CMClass.classID(M2).toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getMyRace().racialCategory().toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getMyRace().name().toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getCurrentClass().name(M2.charStats().getCurrentClassLevel()).toUpperCase().indexOf(mobType)>=0)) choices.add(M2); } } } } catch (final NoSuchElementException e) { } } else { try { for(final MOB M2 : q.mobGroup) { if((M2!=null) &&(M2.isMonster()) &&((M2.amUltimatelyFollowing()==null)||(M2.amUltimatelyFollowing().isMonster()))) { if(mobType.equalsIgnoreCase("any")) choices.add(M2); else if((CMClass.classID(M2).toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getMyRace().racialCategory().toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getMyRace().name().toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getCurrentClass().name(M2.charStats().getCurrentClassLevel()).toUpperCase().indexOf(mobType)>=0)) choices.add(M2); } } } catch (final NoSuchElementException e) { } } } for(int t=0;t<mobTypes.size();t++) { String mobType=mobTypes.elementAt(t); if(!mobType.startsWith("-")) continue; mobType=mobType.substring(1); for(int i=choices.size()-1;i>=0;i--) { final MOB M2=choices.get(i); if((M2!=null) &&(M2.isMonster()) &&((M2.amUltimatelyFollowing()==null)||(M2.amUltimatelyFollowing().isMonster()))) { if((CMClass.classID(M2).toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getMyRace().racialCategory().toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getMyRace().name().toUpperCase().indexOf(mobType)>=0) ||(M2.charStats().getCurrentClass().name(M2.charStats().getCurrentClassLevel()).toUpperCase().indexOf(mobType)>=0) ||(M2.name().toUpperCase().indexOf(mobType)>=0) ||(M2.displayText().toUpperCase().indexOf(mobType)>=0)) choices.remove(M2); } } } this.filterOutThoseInUse(choices, p.toString(), q, isQuiet, reselect); if(choices.size()>0) q.mob=choices.get(CMLib.dice().roll(1,choices.size(),-1)); } if(q.mob==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !mobtype '"+p+"'."); break; } if(reselect) q.reselectable.add(q.mob); // why is this being done -- atm, this is a simple map mob, minding his own business. questifyScriptableBehavs(q.mob); if(q.room!=null) q.room.bringMobHere(q.mob,false); else q.room=q.mob.location(); q.envObject=q.mob; runtimeRegisterObject(q.mob); if(q.room!=null) { q.area=q.room.getArea(); q.room.recoverRoomStats(); q.room.showHappens(CMMsg.MSG_OK_ACTION,null); } } else if(cmd.equals("MOBGROUP")) { q.mobGroup=null; boolean reselect=false; if((p.size()>2)&&(p.elementAt(2).equalsIgnoreCase("reselect"))) { p.removeElementAt(2); reselect=true; } if(p.size()<3) continue; List<MOB> choices=null; String mobName=CMParms.combine(p,2).toUpperCase(); final String maskStr=CMLib.quests().breakOutMaskString(s,p); final MaskingLibrary.CompiledZapperMask mask=(maskStr.trim().length()==0)?null:CMLib.masking().maskCompile(maskStr); if(mask!=null) mobName=CMParms.combine(p,2).toUpperCase(); try { choices=(List)getObjectIfSpecified(p,args,2,1); } catch(final CMException ex) { if(mobName.length()==0) mobName="ANY"; final boolean addAll=mobName.equalsIgnoreCase("all"); final List<MOB> choices0=new Vector<MOB>(); final List<MOB> choices1=new Vector<MOB>(); final List<MOB> choices2=new Vector<MOB>(); final List<MOB> choices3=new Vector<MOB>(); try { for(final Enumeration e=getAppropriateRoomSet(q);e.hasMoreElements();) { final Room R2=(Room)e.nextElement(); for(int i=0;i<R2.numInhabitants();i++) { final MOB M2=R2.fetchInhabitant(i); if((M2!=null) &&(M2.isMonster()) &&((M2.amUltimatelyFollowing()==null)||(M2.amUltimatelyFollowing().isMonster()))) { if(CMLib.masking().maskCheck(mask,M2,true)) { if(addAll) { choices = choices0; choices.add(M2); } else choices=sortSelect(M2,mobName,choices,choices0,choices1,choices2,choices3); } } } } } catch (final NoSuchElementException e) { } this.filterOutThoseInUse(choices, p.toString(), q, isQuiet, reselect); } if((choices!=null)&&(choices.size()>0)) { q.mobGroup=choices; if(reselect) q.reselectable.addAll(choices); } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', !mobgroup '"+mobName+":"+maskStr+"'."); break; } q.envObject=q.mobGroup; } else if(cmd.equals("ITEMGROUP")) { q.itemGroup=null; boolean reselect=false; if((p.size()>2)&&(p.elementAt(2).equalsIgnoreCase("reselect"))) { p.removeElementAt(2); reselect=true; } if(p.size()<3) continue; List<Item> choices=null; String itemName=CMParms.combine(p,2).toUpperCase(); final String maskStr=CMLib.quests().breakOutMaskString(s,p); final MaskingLibrary.CompiledZapperMask mask=(maskStr.trim().length()==0)?null:CMLib.masking().maskCompile(maskStr); if(mask!=null) itemName=CMParms.combine(p,2).toUpperCase(); try { choices=(List)getObjectIfSpecified(p,args,2,1); } catch(final CMException ex) { final List<Item> choices0=new Vector<Item>(); final List<Item> choices1=new Vector<Item>(); final List<Item> choices2=new Vector<Item>(); final List<Item> choices3=new Vector<Item>(); if(itemName.length()==0) itemName="ANY"; final boolean addAll=itemName.equalsIgnoreCase("all"); try { for(final Enumeration e=getAppropriateRoomSet(q);e.hasMoreElements();) { final Room R2=(Room)e.nextElement(); for(int i=0;i<R2.numItems();i++) { final Item I2=R2.getItem(i); if(I2!=null) { if(CMLib.masking().maskCheck(mask,I2,true)) { if(addAll) { choices = choices0; choices.add(I2); } else choices=sortSelect(I2,itemName,choices,choices0,choices1,choices2,choices3); } } } } } catch (final NoSuchElementException e) { } this.filterOutThoseInUse(choices, p.toString(), q, isQuiet, reselect); } if((choices!=null)&&(choices.size()>0)) { if(reselect) q.reselectable.addAll(choices); q.itemGroup=choices; } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', !itemgroup '"+itemName+":"+maskStr+"'."); break; } q.envObject=q.itemGroup; } else if(cmd.equals("ITEMTYPE")) { boolean reselect=false; if((p.size()>2)&&(p.elementAt(2).equalsIgnoreCase("reselect"))) { p.removeElementAt(2); reselect=true; } if(p.size()<3) { q.item=null; continue; } try { q.item=(Item)getObjectIfSpecified(p,args,2,0); } catch(final CMException ex) { q.item=null; final List<Item> choices=new ArrayList<Item>(); final Vector<String> itemTypes=new Vector<String>(); for(int i=2;i<p.size();i++) itemTypes.addElement(p.elementAt(i)); for(int t=0;t<itemTypes.size();t++) { final String itemType=itemTypes.elementAt(t).toUpperCase(); if(itemType.startsWith("-")) continue; try { if(q.itemGroup==null) { for(final Enumeration<Room> e=getAppropriateRoomSet(q);e.hasMoreElements();) { final Room R2=e.nextElement(); for(int i=0;i<R2.numItems();i++) { final Item I2=R2.getItem(i); if((I2!=null)) { if(itemType.equalsIgnoreCase("any")) choices.add(I2); else if(CMClass.classID(I2).toUpperCase().indexOf(itemType)>=0) choices.add(I2); } } } } else { for(final Item I2 : q.itemGroup) { if((I2!=null)) { if(itemType.equalsIgnoreCase("any")) choices.add(I2); else if(CMClass.classID(I2).toUpperCase().indexOf(itemType)>=0) choices.add(I2); } } } } catch(final NoSuchElementException e) { } } for(int t=0;t<itemTypes.size();t++) { String itemType=itemTypes.elementAt(t); if(!itemType.startsWith("-")) continue; itemType=itemType.substring(1); for(int i=choices.size()-1;i>=0;i--) { final Item I2=choices.get(i); if((CMClass.classID(I2).toUpperCase().indexOf(itemType)>=0) ||(I2.name().toUpperCase().indexOf(itemType)>=0) ||(I2.displayText().toUpperCase().indexOf(itemType)>=0)) choices.remove(I2); } } this.filterOutThoseInUse(choices, p.toString(), q, isQuiet, reselect); if(choices.size()>0) q.item=choices.get(CMLib.dice().roll(1,choices.size(),-1)); } if(q.item==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !itemtype '"+p+"'."); break; } questifyScriptableBehavs(q.item); // this really makes little sense, though is harmless if(reselect) q.reselectable.add(q.item); if(q.room!=null) q.room.moveItemTo(q.item,ItemPossessor.Expire.Never,ItemPossessor.Move.Followers); else if(q.item.owner() instanceof Room) q.room=(Room)q.item.owner(); q.envObject=q.item; if(q.room!=null) { q.area=q.room.getArea(); q.room.recoverRoomStats(); q.room.showHappens(CMMsg.MSG_OK_ACTION,null); } } else if(cmd.equals("PRESERVE")) q.preserveState=CMath.parseIntExpression(p.elementAt(2)); else if(cmd.equals("LOCALE")||cmd.equals("LOCALEGROUP")||cmd.equals("LOCALEGROUPAROUND")) { int range=0; if(cmd.equals("LOCALE")) { try { q.room=(Room)getObjectIfSpecified(p,args,2,0); if(q.room!=null) { q.area=q.room.getArea(); q.envObject=q.room; } continue; } catch(final CMException ex) { q.room=null; } } else if(cmd.equals("LOCALEGROUPAROUND")) { q.roomGroup=null; if(p.size()<3) continue; range=CMath.parseIntExpression(p.elementAt(2)); if(range<=0) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !localegrouparound #'"+(p.elementAt(2)+"'.")); break; } p.removeElementAt(2); if(q.room==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', localegrouparound !room."); break; } } else { try { q.roomGroup=(List)getObjectIfSpecified(p,args,2,1); q.envObject=q.roomGroup; continue; } catch(final CMException ex) { q.roomGroup=null; } } if(p.size()<3) continue; final Vector<String> names=new Vector<String>(); if((p.size()>3)&&(p.elementAt(2).equalsIgnoreCase("any"))) { for(int ip=3;ip<p.size();ip++) names.addElement(p.elementAt(ip)); } else names.addElement(CMParms.combine(p,2)); final List<Room> choices=new ArrayList(); List<Room> useThese=null; if(range>0) { TrackingLibrary.TrackingFlags flags; flags = CMLib.tracking().newFlags() .plus(TrackingLibrary.TrackingFlag.AREAONLY); useThese=CMLib.tracking().getRadiantRooms(q.room,flags,range); } final Iterable<Room> list=buildAppropriateRoomIterable(q,useThese); for(int n=0;n<names.size();n++) { final String localeName=names.elementAt(n).toUpperCase(); try { final Iterator<Room> e=list.iterator(); final boolean addAll=(localeName.equalsIgnoreCase("any") ||localeName.equalsIgnoreCase("all")); for(;e.hasNext();) { final Room R2=e.next(); if(addAll||CMClass.classID(R2).toUpperCase().indexOf(localeName)>=0) choices.add(R2); else { final int dom=R2.domainType(); if((dom&Room.INDOORS)>0) { if(Room.DOMAIN_INDOORS_DESCS[dom-Room.INDOORS].indexOf(localeName)>=0) choices.add(R2); } else if(Room.DOMAIN_OUTDOOR_DESCS[dom].indexOf(localeName)>=0) choices.add(R2); } } } catch(final NoSuchElementException e) { } } if(cmd.equalsIgnoreCase("LOCALEGROUP")||cmd.equalsIgnoreCase("LOCALEGROUPAROUND")) { if(choices.size()>0) q.roomGroup=choices; else { errorOccurred(q,isQuiet,"Quest '"+name()+"', !localegroup '"+CMParms.combine(p,2)+"'."); break; } q.envObject=q.roomGroup; } else { if(choices.size()>0) q.room=choices.get(CMLib.dice().roll(1,choices.size(),-1)); if(q.room==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !locale '"+CMParms.combine(p,2)+"'."); break; } q.area=q.room.getArea(); q.envObject=q.room; } } else if(cmd.equals("ROOM")||cmd.equals("ROOMGROUP")||cmd.equals("ROOMGROUPAROUND")) { int range=0; if(cmd.equals("ROOM")) { try { q.room=(Room)getObjectIfSpecified(p,args,2,0); if(q.room!=null) { q.area=q.room.getArea(); q.envObject=q.room; } continue; } catch(final CMException ex) { q.room=null; } } else if(cmd.equals("ROOMGROUPAROUND")) { q.roomGroup=null; if(p.size()<3) continue; range=CMath.s_parseIntExpression(p.elementAt(2)); if(range<=0) { errorOccurred(q,isQuiet,"Quest '"+name()+"' roomgrouparound #'"+(p.elementAt(2)+"'.")); break; } p.removeElementAt(2); if(q.room==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', roomgrouparound !room."); break; } } else { try { q.roomGroup=(List)getObjectIfSpecified(p,args,2,1); q.envObject=q.roomGroup; continue; } catch(final CMException ex) { q.roomGroup=null; } } if(p.size()<3) continue; List<Room> choices=null; final List<Room> choices0=new Vector<Room>(); final List<Room> choices1=new Vector<Room>(); final List<Room> choices2=new Vector<Room>(); final List<Room> choices3=new Vector<Room>(); final Vector<String> names=new Vector<String>(); final String maskStr=CMLib.quests().breakOutMaskString(s,p); final MaskingLibrary.CompiledZapperMask mask=(maskStr.trim().length()==0)?null:CMLib.masking().maskCompile(maskStr); if((p.size()>3)&&(p.elementAt(2).equalsIgnoreCase("any"))) { for(int ip=3;ip<p.size();ip++) names.addElement(p.elementAt(ip)); } else names.addElement(CMParms.combine(p,2)); List<Room> useThese=null; if(range>0) { TrackingLibrary.TrackingFlags flags; flags = CMLib.tracking().newFlags() .plus(TrackingLibrary.TrackingFlag.AREAONLY); useThese=CMLib.tracking().getRadiantRooms(q.room,flags,range); } final Iterable<Room> list=buildAppropriateRoomIterable(q,useThese); for(int n=0;n<names.size();n++) { final String localeName=names.elementAt(n).toUpperCase(); try { final Iterator<Room> e=list.iterator(); final boolean addAll=localeName.equalsIgnoreCase("any") ||localeName.equalsIgnoreCase("all"); for(;e.hasNext();) { final Room R2=e.next(); final String display=R2.displayText().toUpperCase(); final String desc=R2.description().toUpperCase(); if((mask!=null)&&(!CMLib.masking().maskCheck(mask,R2,true))) continue; if(addAll) { choices=choices0; choices0.add(R2); } else if(CMLib.map().getExtendedRoomID(R2).equalsIgnoreCase(localeName)) { choices=choices0; choices0.add(R2); } else if(display.equals(localeName)) { if((choices==null)||(choices==choices2)||(choices==choices3)) choices=choices1; choices1.add(R2); } else if(CMLib.english().containsString(display,localeName)) { if((choices==null)||(choices==choices3)) choices=choices2; choices2.add(R2); } else if(CMLib.english().containsString(desc,localeName)) { if(choices==null) choices=choices3; choices3.add(R2); } } } catch(final NoSuchElementException e) { } } if(cmd.equalsIgnoreCase("ROOMGROUP")||cmd.equalsIgnoreCase("ROOMGROUPAROUND")) { if((choices!=null)&&(choices.size()>0)) q.roomGroup=choices; else { errorOccurred(q,isQuiet,"Quest '"+name()+"', !roomgroup '"+CMParms.combine(p,2)+"'."); break; } q.envObject=q.roomGroup; } else { if((choices!=null)&&(choices.size()>0)) q.room=choices.get(CMLib.dice().roll(1,choices.size(),-1)); if(q.room==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !room '"+CMParms.combine(p,2)+"'."); break; } q.area=q.room.getArea(); q.envObject=q.room; } } else if(cmd.equals("MOB")) { boolean reselect=false; if((p.size()>2)&&(p.elementAt(2).equalsIgnoreCase("reselect"))) { p.removeElementAt(2); reselect=true; } if(p.size()<3) { q.mob=null; continue; } String mobName=CMParms.combine(p,2).toUpperCase(); final String maskStr=CMLib.quests().breakOutMaskString(s,p); final MaskingLibrary.CompiledZapperMask mask=(maskStr.trim().length()==0)?null:CMLib.masking().maskCompile(maskStr); if(mask!=null) mobName=CMParms.combine(p,2).toUpperCase(); try { q.mob=(MOB)getObjectIfSpecified(p,args,2,0); } catch(final CMException ex) { q.mob=null; List<MOB> choices=null; final List<MOB> choices0=new Vector<MOB>(); final List<MOB> choices1=new Vector<MOB>(); final List<MOB> choices2=new Vector<MOB>(); final List<MOB> choices3=new Vector<MOB>(); if(mobName.length()==0) mobName="ANY"; if(q.mobGroup!=null) { for(final MOB M2 : q.mobGroup) { if((M2!=null) &&(M2.isMonster()) &&((M2.amUltimatelyFollowing()==null)||(M2.amUltimatelyFollowing().isMonster()))) { if(!CMLib.masking().maskCheck(mask,M2,true)) continue; choices=sortSelect(M2,mobName,choices,choices0,choices1,choices2,choices3); } } } else { try { for(final Enumeration<Room> e=getAppropriateRoomSet(q);e.hasMoreElements();) { final Room R2=e.nextElement(); for(int i=0;i<R2.numInhabitants();i++) { final MOB M2=R2.fetchInhabitant(i); if((M2!=null) &&(M2.isMonster()) &&((M2.amUltimatelyFollowing()==null)||(M2.amUltimatelyFollowing().isMonster()))) { if(!CMLib.masking().maskCheck(mask,M2,true)) continue; choices=sortSelect(M2,mobName,choices,choices0,choices1,choices2,choices3); } } } } catch(final NoSuchElementException e) { } } this.filterOutThoseInUse(choices, p.toString(), q, isQuiet, reselect); if((choices!=null)&&(choices.size()>0)) q.mob=choices.get(CMLib.dice().roll(1,choices.size(),-1)); } if(q.mob==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !mob '"+mobName+"'."); break; } if(reselect) q.reselectable.add(q.mob); questifyScriptableBehavs(q.mob); // just wierd if(q.room!=null) q.room.bringMobHere(q.mob,false); else q.room=q.mob.location(); if(q.room!=null) { q.area=q.room.getArea(); q.envObject=q.mob; runtimeRegisterObject(q.mob); q.room.recoverRoomStats(); q.room.showHappens(CMMsg.MSG_OK_ACTION,null); } } else if(cmd.equals("ITEM")) { boolean reselect=false; if((p.size()>2)&&(p.elementAt(2).equalsIgnoreCase("reselect"))) { p.removeElementAt(2); reselect=true; } if(p.size()<3) { q.item=null; continue; } String itemName=CMParms.combine(p,2).toUpperCase(); final String maskStr=CMLib.quests().breakOutMaskString(s,p); final MaskingLibrary.CompiledZapperMask mask=(maskStr.trim().length()==0)?null:CMLib.masking().maskCompile(maskStr); if(mask!=null) itemName=CMParms.combine(p,2).toUpperCase(); try { q.item=(Item)getObjectIfSpecified(p,args,2,0); } catch(final CMException ex) { q.item=null; List<Item> choices=null; final List<Item> choices0=new Vector<Item>(); final List<Item> choices1=new Vector<Item>(); final List<Item> choices2=new Vector<Item>(); final List<Item> choices3=new Vector<Item>(); if(itemName.trim().length()==0) itemName="ANY"; try { if(q.itemGroup!=null) { for(final Item I2 : q.itemGroup) { if(I2!=null) { if(!CMLib.masking().maskCheck(mask,I2,true)) continue; choices=sortSelect(I2,itemName,choices,choices0,choices1,choices2,choices3); } } } else { for(final Enumeration<Room> e=getAppropriateRoomSet(q);e.hasMoreElements();) { final Room R2=e.nextElement(); for(int i=0;i<R2.numItems();i++) { final Item I2=R2.getItem(i); if(I2!=null) { if(!CMLib.masking().maskCheck(mask,I2,true)) continue; choices=sortSelect(I2,itemName,choices,choices0,choices1,choices2,choices3); } } } } } catch(final NoSuchElementException e) { } this.filterOutThoseInUse(choices, p.toString(), q, isQuiet, reselect); if((choices!=null)&&(choices.size()>0)) q.item=choices.get(CMLib.dice().roll(1,choices.size(),-1)); } if(q.item==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !item '"+itemName+"'."); break; } if(reselect) q.reselectable.add(q.item); questifyScriptableBehavs(q.item); // here we go again if(q.room!=null) q.room.moveItemTo(q.item,ItemPossessor.Expire.Never,ItemPossessor.Move.Followers); else if(q.item.owner() instanceof Room) q.room=(Room)q.item.owner(); q.envObject=q.item; if(q.room!=null) { q.area=q.room.getArea(); q.room.recoverRoomStats(); q.room.showHappens(CMMsg.MSG_OK_ACTION,null); } } else if(cmd.equals("AGENT")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); try { q.mob=(MOB)getObjectIfSpecified(p,args,2,0); } catch(final CMException ex) { if(p.size()>2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', agent syntax '"+CMParms.combine(p,2)+"'."); break; } } if(q.mob==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', agent !mob."); break; } questifyScriptableBehavs(q.mob); // should be done to loaded or q-scripted mobs only q.mysteryData.agent=q.mob; q.mob=q.mysteryData.agent; q.envObject=q.mob; } else if(cmd.equals("FACTION")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(p.size()<3) continue; final String numStr=CMParms.combine(p,2); Faction F=null; try { F=(Faction)getObjectIfSpecified(p,args,2,0); } catch(final CMException ex) { if(numStr.equalsIgnoreCase("ANY")) { final int numFactions=CMLib.factions().numFactions(); final int whichFaction=CMLib.dice().roll(1,numFactions,-1); int curFaction=0; for(final Enumeration<Faction> e=CMLib.factions().factions();e.hasMoreElements();curFaction++) { F=e.nextElement(); if(curFaction==whichFaction) break; } } else { F=CMLib.factions().getFaction(numStr); if(F==null) F=CMLib.factions().getFactionByName(numStr); } } if(F==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !faction #'"+numStr+"'."); break; } q.mysteryData.faction=F; } else if(cmd.equals("FACTIONGROUP")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(p.size()<3) { q.mysteryData.factionGroup=null; continue; } try { q.mysteryData.factionGroup=(List)getObjectIfSpecified(p,args,2,1); } catch(final CMException ex) { q.mysteryData.factionGroup=null; String numStr=CMParms.combine(p,2); Faction F=null; if(q.mysteryData.faction!=null) q.mysteryData.factionGroup.add(q.mysteryData.faction); if(CMath.isMathExpression(numStr)||numStr.equalsIgnoreCase("ALL")) { final int numFactions=CMLib.factions().numFactions(); if(numStr.equalsIgnoreCase("ALL")) numStr=""+numFactions; int num=CMath.s_parseIntExpression(numStr); if(num>=numFactions) num=numFactions; int tries=500; while((q.mysteryData.factionGroup.size()<num)&&(--tries>0)) { final int whichFaction=CMLib.dice().roll(1,numFactions,-1); int curFaction=0; for(final Enumeration<Faction> e=CMLib.factions().factions();e.hasMoreElements();curFaction++) { F=e.nextElement(); if(curFaction==whichFaction) break; } if(!q.mysteryData.factionGroup.contains(F)) q.mysteryData.factionGroup.add(F); } } else { for(int pi=2;pi<p.size();pi++) { F=CMLib.factions().getFaction(p.elementAt(pi)); if(F==null) F=CMLib.factions().getFactionByName(p.elementAt(pi)); if(F==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !factiongroup '"+p.elementAt(pi)+"'."); break; } if(!q.mysteryData.factionGroup.contains(F)) q.mysteryData.factionGroup.add(F); } if(q.error) break; } } if((q.mysteryData.factionGroup!=null) &&(q.mysteryData.factionGroup.size()>0) &&(q.mysteryData.faction==null)) q.mysteryData.faction=q.mysteryData.factionGroup.get(CMLib.dice().roll(1,q.mysteryData.factionGroup.size(),-1)); } else if(cmd.equals("AGENTGROUP")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(p.size()<3) { q.mysteryData.agentGroup=null; continue; } try { q.mysteryData.agentGroup=(List)getObjectIfSpecified(p,args,2,1); if((q.mysteryData.agentGroup!=null) &&(q.mysteryData.agentGroup.size()>0) &&(q.mysteryData.agent==null)) q.mysteryData.agent=q.mysteryData.agentGroup.get(CMLib.dice().roll(1,q.mysteryData.agentGroup.size(),-1)); } catch(final CMException ex) { q.mysteryData.agentGroup=null; final String numStr=CMParms.combine(p,2).toUpperCase(); if(!CMath.isMathExpression(numStr)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !agentgroup #'"+numStr+"'."); break; } if((q.mobGroup==null)||(q.mobGroup.size()==0)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !agentgroup mobgroup."); break; } final List<MOB> V=new ArrayList<MOB>(); V.addAll(q.mobGroup); q.mysteryData.agentGroup=new Vector<MOB>(); if(q.mysteryData.agent!=null) q.mysteryData.agentGroup.add(q.mysteryData.agent); int num=CMath.parseIntExpression(numStr); if(num>=V.size()) num=V.size(); while((q.mysteryData.agentGroup.size()<num)&&(V.size()>0)) { final int dex=CMLib.dice().roll(1,V.size(),-1); final Object O=V.get(dex); V.remove(dex); q.mysteryData.agentGroup.add((MOB)O); if(q.mysteryData.agent==null) q.mysteryData.agent=(MOB)O; } questifyScriptableBehavs(q.mob); } q.mob=q.mysteryData.agent; if(q.mysteryData.agentGroup!=null) { q.mobGroup=new Vector<MOB>(); q.mobGroup.addAll(q.mysteryData.agentGroup); } q.envObject=q.mysteryData.agentGroup; } else if(cmd.equals("WHEREHAPPENEDGROUP")||cmd.equals("WHEREATGROUP")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(cmd.equals("WHEREHAPPENEDGROUP")) { try { q.mysteryData.whereHappenedGroup=(List)getObjectIfSpecified(p,args,2,1); q.roomGroup=q.mysteryData.whereHappenedGroup; q.mysteryData.whereHappened=((q.roomGroup==null)||(q.roomGroup.size()==0))?null: (Room)q.roomGroup.get(CMLib.dice().roll(1,q.roomGroup.size(),-1)); q.envObject=q.mysteryData.whereHappenedGroup; continue; } catch(final CMException ex) { q.mysteryData.whereHappenedGroup=null; } } else { try { q.mysteryData.whereAtGroup=(List)getObjectIfSpecified(p,args,2,1); q.roomGroup=q.mysteryData.whereAtGroup; q.mysteryData.whereAt=((q.roomGroup==null)||(q.roomGroup.size()==0))?null: (Room)q.roomGroup.get(CMLib.dice().roll(1,q.roomGroup.size(),-1)); q.envObject=q.mysteryData.whereAtGroup; continue; } catch(final CMException ex) { q.mysteryData.whereAtGroup=null; } } if(p.size()<3) continue; final String numStr=CMParms.combine(p,2).toUpperCase(); if(!CMath.isMathExpression(numStr)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !"+cmd.toLowerCase()+" #'"+numStr+"'."); break; } if((q.roomGroup==null)||(q.roomGroup.size()==0)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !"+cmd.toLowerCase()+" roomGroup."); break; } final List<Room> V=new ArrayList<Room>(); V.addAll(q.roomGroup); final List<Room> V2=new Vector<Room>(); Room R=null; if(cmd.equals("WHEREHAPPENEDGROUP")) { q.mysteryData.whereHappenedGroup=V2; R=q.mysteryData.whereHappened; } else { q.mysteryData.whereAtGroup=null; R=q.mysteryData.whereAt; } if(R!=null) V2.add(R); int num=CMath.parseIntExpression(numStr); if(num>=V.size()) num=V.size(); while((V2.size()<num)&&(V.size()>0)) { final int dex=CMLib.dice().roll(1,V.size(),-1); final Room O=V.get(dex); V.remove(dex); if(!V2.contains(O)) V2.add(O); if(R==null) R=O; } q.roomGroup=new Vector<Room>(); q.roomGroup.addAll(V2); q.room=R; q.envObject=q.roomGroup; if(cmd.equals("WHEREHAPPENEDGROUP")) q.mysteryData.whereHappened=R; else q.mysteryData.whereAt=R; } else if(cmd.equals("WHENHAPPENEDGROUP")||cmd.equals("WHENATGROUP")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); List<TimeClock> V2; TimeClock TC=null; if(cmd.equals("WHENHAPPENEDGROUP")) { try { q.mysteryData.whenHappenedGroup=(List)getObjectIfSpecified(p,args,2,1); V2=q.mysteryData.whenHappenedGroup; if((V2!=null)&&(V2.size()>0)) q.mysteryData.whenHappened=V2.get(CMLib.dice().roll(1,V2.size(),-1)); continue; } catch(final CMException ex) { q.mysteryData.whenHappenedGroup=null; } } else { try { q.mysteryData.whenAtGroup=(List)getObjectIfSpecified(p,args,2,1); V2=q.mysteryData.whenAtGroup; if((V2!=null)&&(V2.size()>0)) q.mysteryData.whenAt=V2.get(CMLib.dice().roll(1,V2.size(),-1)); continue; } catch(final CMException ex) { q.mysteryData.whenAtGroup=null; } } if(p.size()<3) continue; V2=new Vector<TimeClock>(); final TimeClock NOW=getMysteryTimeNowFromState(); if(cmd.equals("WHENHAPPENEDGROUP")) { q.mysteryData.whenHappenedGroup=V2; TC=q.mysteryData.whenHappened; } else { q.mysteryData.whenAtGroup=V2; TC=q.mysteryData.whenAt; } for(int pi=2;pi<p.size();pi++) { final String numStr=p.elementAt(pi); if(!CMath.isMathExpression(numStr)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', "+cmd.toLowerCase()+" !relative hour #: "+numStr+"."); break; } final TimeClock TC2=(TimeClock)NOW.copyOf(); TC2.tickTock(CMath.parseIntExpression(numStr)); V2.add(TC2); } if(q.error) break; if((V2.size()>0)&&(TC==null)) TC=V2.get(CMLib.dice().roll(1,V2.size(),-1)); if(cmd.equals("WHENHAPPENEDGROUP")) q.mysteryData.whenHappened=TC; else q.mysteryData.whenAt=TC; } else if(cmd.equals("WHENHAPPENED") ||cmd.equals("WHENAT")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(cmd.equals("WHENHAPPENED")) { try { q.mysteryData.whenHappened=(TimeClock)getObjectIfSpecified(p,args,2,0); continue; } catch(final CMException ex) { q.mysteryData.whenHappened=null; } } else { try { q.mysteryData.whenAt=(TimeClock)getObjectIfSpecified(p,args,2,0); continue; } catch(final CMException ex) { q.mysteryData.whenAt=null; } } if(p.size()<3) continue; final TimeClock NOW=getMysteryTimeNowFromState(); TimeClock TC=null; final String numStr=CMParms.combine(p,2); if(!CMath.isMathExpression(numStr)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', "+cmd.toLowerCase()+" !relative hour #: "+numStr+"."); break; } TC=(TimeClock)NOW.copyOf(); TC.tickTock(CMath.parseIntExpression(numStr)); if(cmd.equals("WHENHAPPENED")) q.mysteryData.whenHappened=TC; else q.mysteryData.whenAt=TC; } else if(cmd.equals("MOTIVEGROUP")||cmd.equals("ACTIONGROUP")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); List<String> V2=null; int num=-1; if((p.size()>2)&&(CMath.isMathExpression(p.elementAt(2)))) { num=CMath.s_parseIntExpression(p.elementAt(2)); p.removeElementAt(2); } if(cmd.equals("MOTIVEGROUP")) { try { q.mysteryData.motiveGroup=(List)getObjectIfSpecified(p,args,2,1); sizeDownTo(q.mysteryData.motiveGroup,num); V2=q.mysteryData.motiveGroup; if((V2!=null)&&(V2.size()>0)) q.mysteryData.motive=V2.get(CMLib.dice().roll(1,V2.size(),-1)); continue; } catch(final CMException ex) { q.mysteryData.motiveGroup=null; } } else { try { q.mysteryData.actionGroup=(List)getObjectIfSpecified(p,args,2,1); sizeDownTo(q.mysteryData.actionGroup,num); V2=q.mysteryData.actionGroup; if((V2!=null)&&(V2.size()>0)) q.mysteryData.action=V2.get(CMLib.dice().roll(1,V2.size(),-1)); continue; } catch(final CMException ex) { q.mysteryData.actionGroup=null; } } if(p.size()<3) continue; V2=new Vector<String>(); String Mstr=null; if(cmd.equals("MOTIVEGROUP")) { q.mysteryData.motiveGroup=V2; Mstr=q.mysteryData.motive; } else { q.mysteryData.actionGroup=V2; Mstr=q.mysteryData.action; } if(Mstr!=null) V2.add(Mstr); for(int pi=2;pi<p.size();pi++) if(!V2.contains(p.elementAt(pi))) V2.add(p.elementAt(pi)); sizeDownTo(V2,num); if((V2.size()>0)&&(Mstr==null)) Mstr=V2.get(CMLib.dice().roll(1,V2.size(),-1)); if(cmd.equals("MOTIVEGROUP")) q.mysteryData.motive=Mstr; else q.mysteryData.action=Mstr; } else if(cmd.equals("MOTIVE")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(p.size()<3) continue; try { q.mysteryData.motive=(String)getObjectIfSpecified(p,args,2,0); continue; } catch(final CMException ex) { q.mysteryData.motive=null; } q.mysteryData.motive=CMParms.combine(p,2); } else if(cmd.equals("ACTION")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(p.size()<3) continue; try { q.mysteryData.action=(String)getObjectIfSpecified(p,args,2,0); continue; } catch(final CMException ex) { q.mysteryData.action=null; } q.mysteryData.action=CMParms.combine(p,2); } else if(cmd.equals("WHEREHAPPENED") ||cmd.equals("WHEREAT")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(cmd.equals("WHEREHAPPENED")) { try { q.mysteryData.whereHappened=(Room)getObjectIfSpecified(p,args,2,0); q.room=q.mysteryData.whereHappened; q.envObject=q.room; continue; } catch(final CMException ex) { q.mysteryData.whereHappened=null; } } else { try { q.mysteryData.whereAt=(Room)getObjectIfSpecified(p,args,2,0); q.room=q.mysteryData.whereAt; q.envObject=q.room; continue; } catch(final CMException ex) { q.mysteryData.whereAt=null; } } if(p.size()>2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', "+cmd.toLowerCase()+" syntax '"+CMParms.combine(p,2)+"'."); break; } if(q.room==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', "+cmd.toLowerCase()+" !room."); break; } if(cmd.equals("WHEREHAPPENED")) q.mysteryData.whereHappened=q.room; else q.mysteryData.whereAt=q.room; q.envObject=q.room; } else if(cmd.equals("TARGETGROUP") ||cmd.equals("TOOLGROUP")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); List V2=null; if(cmd.equals("TARGETGROUP")) { try { q.mysteryData.targetGroup=(List)getObjectIfSpecified(p,args,2,1); V2=q.mysteryData.targetGroup; if((V2!=null)&&(V2.size()>0)) { if(V2.get(0) instanceof MOB) { q.mobGroup=V2; q.mob=(MOB)V2.get(CMLib.dice().roll(1,V2.size(),-1)); q.envObject=q.mobGroup; q.mysteryData.target=q.mob; } if(V2.get(0) instanceof Item) { q.itemGroup=V2; q.item=(Item)V2.get(CMLib.dice().roll(1,V2.size(),-1)); q.mysteryData.target=q.item; q.envObject=q.itemGroup; } } continue; } catch(final CMException ex) { q.mysteryData.targetGroup=null; } } else { try { q.mysteryData.toolGroup=(List)getObjectIfSpecified(p,args,2,1); V2=q.mysteryData.toolGroup; if((V2!=null)&&(V2.size()>0)) { if(V2.get(0) instanceof MOB) { q.mobGroup=V2; q.mob=(MOB)V2.get(CMLib.dice().roll(1,V2.size(),-1)); q.envObject=q.mobGroup; q.mysteryData.tool=q.mob; } if(V2.get(0) instanceof Item) { q.itemGroup=V2; q.item=(Item)V2.get(CMLib.dice().roll(1,V2.size(),-1)); q.envObject=q.itemGroup; q.mysteryData.tool=q.item; } } continue; } catch(final CMException ex) { q.mysteryData.toolGroup=null; } } if(p.size()<3) continue; final String numStr=CMParms.combine(p,2).toUpperCase(); if(!CMath.isMathExpression(numStr)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !"+cmd.toLowerCase()+" #'"+numStr+"'."); break; } if(((q.mobGroup==null)||(q.mobGroup.size()==0)) &&((q.itemGroup==null)||(q.itemGroup.size()==0))) { errorOccurred(q,isQuiet,"Quest '"+name()+"', !"+cmd.toLowerCase()+" mobgroup itemgroup."); break; } final List<Environmental> V=new ArrayList<Environmental>(); if((q.mobGroup!=null)&&(q.mobGroup.size()>0)) V.addAll(q.mobGroup); else V.addAll(q.itemGroup); V2=new Vector<Environmental>(); Environmental finalE=null; if(cmd.equals("TARGETGROUP")) { q.mysteryData.targetGroup=V2; finalE=q.mysteryData.target; } else { q.mysteryData.toolGroup=V2; finalE=q.mysteryData.tool; } if(finalE!=null) V2.add(finalE); int num=CMath.parseIntExpression(numStr); if(num>=V.size()) num=V.size(); Object O; while((V2.size()<num)&&(V.size()>0)) { final int dex=CMLib.dice().roll(1,V.size(),-1); O=V.get(dex); V.remove(dex); if(!V2.contains(O)) V2.add(O); if(finalE==null) finalE=(Environmental)O; } if(finalE instanceof MOB) { q.mobGroup=new Vector<MOB>(); q.mobGroup.addAll(V2); q.mob=(MOB)finalE; questifyScriptableBehavs(q.mob); // i just dont get it } else if(finalE instanceof Item) { q.itemGroup=new Vector<Item>(); q.itemGroup.addAll(V2); q.item=(Item)finalE; questifyScriptableBehavs(q.item); } q.envObject=V2; if(cmd.equals("TARGETGROUP")) q.mysteryData.target=finalE; else q.mysteryData.tool=finalE; } else if(cmd.equals("TARGET") ||cmd.equals("TOOL")) { if(q.mysteryData==null) q.mysteryData=new MysteryData(); if(cmd.equals("TARGET")) { try { q.mysteryData.target=(Environmental)getObjectIfSpecified(p,args,2,0); if(q.mysteryData.target instanceof MOB) q.mob=(MOB)q.mysteryData.target; if(q.mysteryData.target instanceof Item) q.item=(Item)q.mysteryData.target; q.envObject=q.mysteryData.target; continue; } catch(final CMException ex) { q.mysteryData.target=null; } } else { try { q.mysteryData.tool=(Environmental)getObjectIfSpecified(p,args,2,0); if(q.mysteryData.tool instanceof MOB) q.mob=(MOB)q.mysteryData.tool; if(q.mysteryData.tool instanceof Item) q.item=(Item)q.mysteryData.tool; q.envObject=q.mysteryData.tool; continue; } catch(final CMException ex) { q.mysteryData.tool=null; } } if(p.size()>2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', "+cmd.toLowerCase()+" syntax '"+CMParms.combine(p,2)+"'."); break; } if((q.envObject instanceof List) &&(((List)q.envObject).size()>0) &&(((List)q.envObject).get(0) instanceof Environmental)) q.envObject=((List)q.envObject).get(CMLib.dice().roll(1,((List)q.envObject).size(),-1)); if(!(q.envObject instanceof Environmental)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', "+cmd.toLowerCase()+" !object."); break; } if(cmd.equals("TARGET")) q.mysteryData.target=(Environmental)q.envObject; else q.mysteryData.tool=(Environmental)q.envObject; if(q.envObject instanceof MOB) { q.mob=(MOB)q.envObject; questifyScriptableBehavs(q.mob); // useless, but harmless } else if(q.envObject instanceof Item) { q.item=(Item)q.envObject; questifyScriptableBehavs(q.item); } } else if(!isStat(cmd)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown variable '"+cmd+"'."); break; } } else if(cmd.equals("IMPORT")) { if(p.size()<2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', no IMPORT type."); break; } cmd=p.elementAt(1).toUpperCase(); if(cmd.equals("MOBS")) { if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', no IMPORT MOBS file."); break; } final StringBuffer buf=getResourceFileData(CMParms.combine(p,2), true); if((buf==null)||(buf.length()<20)) { errorOccurred(q,isQuiet,"Quest '"+name()+"',Unknown XML file: '"+CMParms.combine(p,2)+"' for '"+name()+"'."); break; } if(buf.substring(0,20).indexOf("<MOBS>")<0) { errorOccurred(q,isQuiet,"Quest '"+name()+"', Invalid XML file: '"+CMParms.combine(p,2)+"' for '"+name()+"'."); break; } q.loadedMobs=new Vector<MOB>(); final String errorStr=CMLib.coffeeMaker().addMOBsFromXML(buf.toString(),q.loadedMobs,null); if(errorStr.length()>0) { errorOccurred(q,isQuiet,"Quest '"+name()+"',Error on import of: '"+CMParms.combine(p,2)+"' for '"+name()+"': "+errorStr+"."); break; } if(q.loadedMobs.size()<=0) { errorOccurred(q,isQuiet,"Quest '"+name()+"',No mobs loaded: '"+CMParms.combine(p,2)+"' for '"+name()+"'."); break; } for(MOB M : q.loadedMobs) { M.basePhyStats().setRejuv(PhyStats.NO_REJUV); M.basePhyStats().setDisposition(M.basePhyStats().disposition()|PhyStats.IS_UNSAVABLE); M.recoverPhyStats(); M.text(); } } else if(cmd.equals("ITEMS")) { if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', no import filename!"); break; } final StringBuffer buf=getResourceFileData(CMParms.combine(p,2), true); if((buf==null)||(buf.length()<20)) { errorOccurred(q,isQuiet,"Quest '"+name()+"',Unknown XML file: '"+CMParms.combine(p,2)+"' for '"+name()+"'."); break; } if(buf.substring(0,20).indexOf("<ITEMS>")<0) { errorOccurred(q,isQuiet,"Quest '"+name()+"',Invalid XML file: '"+CMParms.combine(p,2)+"' for '"+name()+"'."); break; } q.loadedItems=new Vector<Item>(); final String errorStr=CMLib.coffeeMaker().addItemsFromXML(buf.toString(),q.loadedItems,null); if(errorStr.length()>0) { errorOccurred(q,isQuiet,"Quest '"+name()+"',Error on import of: '"+CMParms.combine(p,2)+"' for '"+name()+"': "+errorStr+"."); break; } if(q.loadedItems.size()<=0) { errorOccurred(q,isQuiet,"Quest '"+name()+"',No items loaded: '"+CMParms.combine(p,2)+"' for '"+name()+"'."); break; } for(Item I : q.loadedItems) { I.basePhyStats().setRejuv(PhyStats.NO_REJUV); I.basePhyStats().setDisposition(I.basePhyStats().disposition()|PhyStats.IS_UNSAVABLE); I.recoverPhyStats(); I.text(); } } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown import type '"+cmd+"'."); break; } } else if(cmd.startsWith("LOAD=")) { final boolean error=q.error; final List<Object> args2=new Vector<Object>(); parseQuestScriptWArgs(parseLoadScripts(s,args,args2,true),args2); if((!error)&&(q.error)) break; } else if(cmd.equals("LOAD")) { if(p.size()<2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', unfound type on load."); break; } cmd=p.elementAt(1).toUpperCase(); if(cmd.equals("MOB")||cmd.equals("MOBGROUP")) { if(q.loadedMobs.size()==0) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot load mob, no mobs imported."); break; } int maxToLoad=Integer.MAX_VALUE; if((p.size()>2)&&(CMath.isMathExpression(p.elementAt(2)))) { maxToLoad=CMath.parseIntExpression(p.elementAt(2)); p.removeElementAt(2); } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', no mob name to load!"); break; } String mobName=CMParms.combine(p,2); final String maskStr=CMLib.quests().breakOutMaskString(s,p); final MaskingLibrary.CompiledZapperMask mask=(maskStr.trim().length()==0)?null:CMLib.masking().maskCompile(maskStr); if(mask!=null) mobName=CMParms.combine(p,2).toUpperCase(); if(mobName.length()==0) mobName="ANY"; final boolean addAll=mobName.equalsIgnoreCase("ALL") ||mobName.equalsIgnoreCase("ANY"); final List<MOB> choices=new Vector<MOB>(); for(int i=0;i<q.loadedMobs.size();i++) { final MOB M2=q.loadedMobs.get(i); if((CMLib.masking().maskCheck(mask,M2,true)) &&(addAll ||(CMLib.english().containsString(M2.name(),mobName)) ||(CMLib.english().containsString(M2.displayText(),mobName)) ||(CMLib.english().containsString(M2.description(),mobName)))) choices.add((MOB)M2.copyOf()); } if(choices.size()==0) { errorOccurred(q,isQuiet,"Quest '"+name()+"', no mob found to load '"+mobName+"'!"); break; } final List<MOB> mobsToDo=new Vector<MOB>(); if(cmd.equalsIgnoreCase("MOB")) mobsToDo.add(choices.get(CMLib.dice().roll(1,choices.size(),-1))); else { mobsToDo.addAll(choices); q.mobGroup=mobsToDo; } while((mobsToDo.size()>maxToLoad)&&(maxToLoad>0)) mobsToDo.remove(CMLib.dice().roll(1,mobsToDo.size(),-1)); while((mobsToDo.size()<maxToLoad)&&(maxToLoad>0)&&(maxToLoad<Integer.MAX_VALUE)) mobsToDo.add((MOB)mobsToDo.get(CMLib.dice().roll(1,mobsToDo.size(),-1)).copyOf()); final Room choiceRoom=q.room; for(int m=0;m<mobsToDo.size();m++) { q.mob=mobsToDo.get(m); q.room=choiceRoom; if(q.room==null) { if(q.roomGroup!=null) q.room=q.roomGroup.get(CMLib.dice().roll(1,q.roomGroup.size(),-1)); else if(q.area!=null) q.room=q.area.getRandomMetroRoom(); else q.room=CMLib.map().getRandomRoom(); } if(q.room!=null) { q.mob.setStartRoom(null); q.mob.basePhyStats().setRejuv(PhyStats.NO_REJUV); q.mob.basePhyStats().setDisposition(q.mob.basePhyStats().disposition()|PhyStats.IS_UNSAVABLE); q.mob.recoverPhyStats(); q.mob.text(); q.mob.bringToLife(q.room,true); } questifyScriptableBehavs(q.mob); runtimeRegisterObject(q.mob); if(q.room!=null) { q.room.recoverRoomStats(); q.room.showHappens(CMMsg.MSG_OK_ACTION,null); } if(q.mob!=null) q.mob.setStartRoom(null); // necessary to tell qm to clean him UP! } q.envObject=mobsToDo; if(q.room!=null) q.area=q.room.getArea(); } else if(cmd.equals("ITEM")||cmd.equals("ITEMGROUP")) { if(q.loadedItems.size()==0) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot load item, no items imported."); break; } int maxToLoad=Integer.MAX_VALUE; if((p.size()>2)&&(CMath.isMathExpression(p.elementAt(2)))) { maxToLoad=CMath.parseIntExpression(p.elementAt(2)); p.removeElementAt(2); } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', no item name to load!"); break; } final String itemName=CMParms.combine(p,2); final List<Item> choices=new Vector<Item>(); for(int i=0;i<q.loadedItems.size();i++) { final Item I2=q.loadedItems.get(i); if((itemName.equalsIgnoreCase("any")) ||(CMLib.english().containsString(I2.name(),itemName)) ||(CMLib.english().containsString(I2.displayText(),itemName)) ||(CMLib.english().containsString(I2.description(),itemName))) choices.add((Item)I2.copyOf()); } if(choices.size()==0) { errorOccurred(q,isQuiet,"Quest '"+name()+"', no item found to load '"+itemName+"'!"); break; } final List<Item> itemsToDo=new Vector<Item>(); if(cmd.equalsIgnoreCase("ITEM")) itemsToDo.add(choices.get(CMLib.dice().roll(1,choices.size(),-1))); else { itemsToDo.addAll(choices); q.itemGroup=choices; } while((itemsToDo.size()>maxToLoad)&&(maxToLoad>0)) itemsToDo.remove(CMLib.dice().roll(1,itemsToDo.size(),-1)); while((itemsToDo.size()<maxToLoad)&&(maxToLoad>0)&&(maxToLoad<Integer.MAX_VALUE)) itemsToDo.add((Item)(itemsToDo.get(CMLib.dice().roll(1,itemsToDo.size(),-1))).copyOf()); final Room choiceRoom=q.room; for(int m=0;m<itemsToDo.size();m++) { q.item=itemsToDo.get(m); q.room=choiceRoom; if(q.room==null) { if(q.roomGroup!=null) q.room=q.roomGroup.get(CMLib.dice().roll(1,q.roomGroup.size(),-1)); else if(q.area!=null) q.room=q.area.getRandomMetroRoom(); else q.room=CMLib.map().getRandomRoom(); } if(q.room!=null) { q.item.basePhyStats().setRejuv(PhyStats.NO_REJUV); q.item.basePhyStats().setDisposition(q.item.basePhyStats().disposition()|PhyStats.IS_UNSAVABLE); q.item.recoverPhyStats(); q.item.text(); q.room.addItem(q.item); q.room.recoverRoomStats(); q.room.showHappens(CMMsg.MSG_OK_ACTION,null); } questifyScriptableBehavs(q.item); runtimeRegisterObject(q.item); } if(q.room!=null) q.area=q.room.getArea(); q.envObject=itemsToDo; } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown load type '"+cmd+"'."); break; } } else if(cmd.equals("GIVE")) { if(p.size()<2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', unfound type on give."); break; } cmd=p.elementAt(1).toUpperCase(); if(cmd.equals("FOLLOWER")) { if(q.mob==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give follower, no mob set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give follower, follower name not given."); break; } final String mobName=CMParms.combine(p,2); final List<MOB> choices=new Vector<MOB>(); ReverseEnumeration<PreservedQuestObject> e; for(e=new ReverseEnumeration<PreservedQuestObject>(q.worldObjects);e.hasMoreElements();) { final PreservedQuestObject PO=e.nextElement(); if((PO.obj!=q.mob)&&(PO.obj instanceof MOB)) { final MOB M2=(MOB)PO.obj; if((mobName.equalsIgnoreCase("any")) ||(CMLib.english().containsString(M2.name(),mobName)) ||(CMLib.english().containsString(M2.displayText(),mobName)) ||(CMLib.english().containsString(M2.description(),mobName))) choices.add(M2); } } if(choices.size()==0) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give follower, no mobs called '"+mobName+"' previously set in script."); break; } final MOB M2=choices.get(CMLib.dice().roll(1,choices.size(),-1)); M2.setFollowing(q.mob); } else if(cmd.equals("ITEM")||(cmd.equalsIgnoreCase("ITEMS"))) { if((q.item==null)&&(q.itemGroup==null)&&(q.loadedItems==null)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give item(s), no item(s) set or loaded."); break; } if((q.mob==null)&&(q.mobGroup==null)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give item(s), no mob set."); break; } if(p.size()>2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give item(s), parameter unnecessarily given: '"+CMParms.combine(p,2)+"'."); break; } final List<MOB> toSet=new Vector<MOB>(); if(q.mob!=null) toSet.add(q.mob); else if(q.mobGroup!=null) toSet.addAll(q.mobGroup); final List<Item> itemSet=new Vector<Item>(); if(q.item!=null) itemSet.add(q.item); else if(q.itemGroup!=null) itemSet.addAll(q.itemGroup); else if(q.loadedItems!=null) itemSet.addAll(q.loadedItems); for(int i=0;i<toSet.size();i++) { final MOB M2=toSet.get(i); runtimeRegisterObject(M2); if(cmd.equals("ITEMS")) { for(int i3=0;i3<itemSet.size();i3++) { Item I3=itemSet.get(i3); if(q.item==I3) { M2.moveItemTo(I3); q.item=(Item)q.item.copyOf(); questifyScriptableBehavs(q.item); } else { I3=(Item)I3.copyOf(); questifyScriptableBehavs(I3); M2.moveItemTo(I3); } } } else if(cmd.equals("ITEM")) { Item I3=itemSet.get(CMLib.dice().roll(1,itemSet.size(),-1)); questifyScriptableBehavs(I3); if(q.item==I3) { M2.moveItemTo(I3); q.item=(Item)q.item.copyOf(); questifyScriptableBehavs(q.item); } else { I3=(Item)I3.copyOf(); questifyScriptableBehavs(I3); M2.moveItemTo(I3); } } } } else if(cmd.equals("ABILITY")) { if((q.mob==null)&&(q.mobGroup==null)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give ability, no mob set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give ability, ability name not given."); break; } final Ability A3=CMClass.findAbility(p.elementAt(2)); if(A3==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give ability, ability name unknown '"+(p.elementAt(2))+"."); break; } final List<MOB> toSet=new Vector<MOB>(); if(q.mob!=null) toSet.add(q.mob); else if(q.mobGroup!=null) toSet.addAll(q.mobGroup); for(int i=0;i<toSet.size();i++) { final MOB M2=toSet.get(i); runtimeRegisterAbility(M2,A3.ID(),CMParms.combineQuoted(p,3),true); } } else if(cmd.equals("BEHAVIOR")) { if(q.envObject==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give behavior, no mob or item set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give behavior, behavior name not given."); break; } final Behavior B=CMClass.getBehavior(p.elementAt(2)); if(B==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give behavior, behavior name unknown '"+(p.elementAt(2))+"."); break; } List toSet=new Vector(); if(q.envObject instanceof List) toSet=(List)q.envObject; else if(q.envObject!=null) toSet.add(q.envObject); for(int i=0;i<toSet.size();i++) { final Environmental E2=(Environmental)toSet.get(i); if(E2 instanceof PhysicalAgent) runtimeRegisterBehavior((PhysicalAgent)E2,B.ID(),CMParms.combineQuoted(p,3),true); } } else if(cmd.equals("STAT")) { if(q.envObject==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give stat, no mob or item set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give stat, stat name not given."); break; } final String stat=p.elementAt(2); final String val=CMParms.combineQuoted(p,3); List<Object> toSet=new Vector<Object>(); if(q.envObject instanceof List) toSet=(List)q.envObject; else if(q.envObject!=null) toSet.add(q.envObject); for(int i=0;i<toSet.size();i++) { final Environmental E2=(Environmental)toSet.get(i); if(stat.equalsIgnoreCase("KEYPLAYER") && (E2 instanceof Physical)) { final Ability A=((Physical)E2).fetchEffect("QuestBound"); if(A!=null) A.setStat("KEY",val); } else runtimeRegisterStat(E2,stat,val,true); } } else if(cmd.equals("SCRIPT")) { if(q.envObject==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give script, no object set."); break; } boolean proceed=true; boolean savable=false; String word=null; String scope=CMStrings.replaceAll(name()," ","_").toUpperCase().trim(); while(proceed&&(p.size()>2)) { word=p.elementAt(2); proceed=false; if(word.equalsIgnoreCase("SAVABLE")) { savable=true; proceed=true; } else if(word.equalsIgnoreCase("GLOBAL")) { scope=""; proceed=true; } else if(word.equalsIgnoreCase("INDIVIDUAL")||word.equals("*")) { scope="*"; proceed=true; } if(proceed) p.removeElementAt(2); } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give script, script not given."); break; } final String val=CMParms.combineQuoted(p,2); List toSet=new Vector(); if(q.envObject instanceof List) toSet=(List)q.envObject; else if(q.envObject!=null) toSet.add(q.envObject); for(int i=0;i<toSet.size();i++) { final Environmental E2=(Environmental)toSet.get(i); if(E2 instanceof PhysicalAgent) { final ScriptingEngine S=(ScriptingEngine)CMClass.getCommon("DefaultScriptingEngine"); S.setSavable(savable); S.registerDefaultQuest(name()); S.setVarScope(scope); S.setScript(val); ((PhysicalAgent)E2).addScript(S); runtimeRegisterObject(((PhysicalAgent)E2)); synchronized(questState) { questState.addons.addElement(new XVector(E2,S),Integer.valueOf(questState.preserveState)); } } } } else if(cmd.equals("AFFECT")) { if(q.envObject==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give Effect, no mob, room or item set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give Effect, ability name not given."); break; } final Ability A3=CMClass.findAbility(p.elementAt(2)); if(A3==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot give Effect, ability name unknown '"+(p.elementAt(2))+"."); break; } List toSet=new Vector(); if(q.envObject instanceof List) toSet=(List)q.envObject; else if(q.envObject!=null) toSet.add(q.envObject); for(final Object o : toSet) { if(o instanceof PhysicalAgent) runtimeRegisterEffect((PhysicalAgent)o,A3.ID(),CMParms.combineQuoted(p,3),true); } } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown give type '"+cmd+"'."); break; } } else if(cmd.equals("TAKE")) { if(p.size()<2) { errorOccurred(q,isQuiet,"Quest '"+name()+"', unfound type on take."); break; } cmd=p.elementAt(1).toUpperCase(); if(cmd.equals("ABILITY")) { if((q.mob==null)&&(q.mobGroup==null)) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take ability, no mob set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take ability, ability name not given."); break; } final Ability A3=CMClass.findAbility(p.elementAt(2)); if(A3==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take ability, ability name unknown '"+(p.elementAt(2))+"."); break; } final List<MOB> toSet=new Vector<MOB>(); if(q.mob!=null) toSet.add(q.mob); else if(q.mobGroup!=null) toSet.addAll(q.mobGroup); for(int i=0;i<toSet.size();i++) { final MOB M2=toSet.get(i); runtimeRegisterAbility(M2,A3.ID(),CMParms.combineQuoted(p,3),false); } } else if(cmd.equals("BEHAVIOR")) { if(q.envObject==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take behavior, no mob or item set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take behavior, behavior name not given."); break; } final Behavior B=CMClass.getBehavior(p.elementAt(2)); if(B==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take behavior, behavior name unknown '"+(p.elementAt(2))+"."); break; } List toSet=new Vector(); if(q.envObject instanceof List) toSet=(List)q.envObject; else if(q.envObject!=null) toSet.add(q.envObject); for(int i=0;i<toSet.size();i++) { final Environmental E2=(Environmental)toSet.get(i); if(E2 instanceof PhysicalAgent) runtimeRegisterBehavior((PhysicalAgent)E2,B.ID(),CMParms.combineQuoted(p,3),false); } } else if(cmd.equals("AFFECT")) { if(q.envObject==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take Effect, no mob, room or item set."); break; } if(p.size()<3) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take Effect, ability name not given."); break; } final Ability A3=CMClass.findAbility(p.elementAt(2)); if(A3==null) { errorOccurred(q,isQuiet,"Quest '"+name()+"', cannot take Effect, ability name unknown '"+(p.elementAt(2))+"."); break; } List toSet=new Vector(); if(q.envObject instanceof List) toSet=(List)q.envObject; else if(q.envObject!=null) toSet.add(q.envObject); for(final Object o : toSet) { if(o instanceof PhysicalAgent) runtimeRegisterEffect((PhysicalAgent)o,A3.ID(),CMParms.combineQuoted(p,3),false); } } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown take type '"+cmd+"'."); break; } } else { errorOccurred(q,isQuiet,"Quest '"+name()+"', unknown command '"+cmd+"'."); break; } q.done=true; } } } public boolean spawnQuest(String script, Vector baseVars, boolean reTime) { final DefaultQuest Q2=(DefaultQuest)CMClass.getCommon("DefaultQuest"); Q2.setCopy(true); Q2.setVars(baseVars,0); Q2.setScript(script,true); CMLib.quests().addQuest(Q2); if(reTime) { Long ellapsed=stepEllapsedTimes.get(script); if(ellapsed==null) ellapsed=Long.valueOf(0); stepEllapsedTimes.remove(script); ellapsed=Long.valueOf(ellapsed.longValue()+(System.currentTimeMillis()-lastStartDateTime)); stepEllapsedTimes.put(script,ellapsed); Q2.resetWaitRemaining(ellapsed.longValue()); if(Q2.startQuestOnTime()) { stepEllapsedTimes.remove(script); return true; } } else if(Q2.startQuestInternal()) return true; Q2.enterDormantState(); return false; } @Override public boolean startQuest() { if((!running())&&(!isCopy())) CMLib.coffeeTables().bump(this,CoffeeTableRow.STAT_QUESTSTARTATTEMPT); return startQuestInternal(); } // this will execute the quest script. If the quest is running, it // will call stopQuestInternal first to shut it down. public boolean startQuestInternal() { if(running()) { stopQuestInternal(); resetData=null; } final List args=new Vector(); questState=new QuestState(); final Vector baseScript=parseLoadScripts(script(),new Vector(),args,true); if((!isCopy())&&(getSpawn()!=SPAWN_NO)) { if(getSpawn()==SPAWN_FIRST) spawnQuest(script(),baseScript,false); else if(getSpawn()==SPAWN_ANY) { final List<String> parsed=CMLib.quests().parseQuestSteps(baseScript,0,false); for(int p=0;p<parsed.size();p++) spawnQuest(parsed.get(p),baseScript,true); } lastStartDateTime=System.currentTimeMillis(); enterDormantState(); return false; // always return false, since, per se, this quest is NOT started. } try { parseQuestScript(baseScript,args,0); } catch(final Exception t) { questState.error=true; Log.errOut("DefaultQuest",t); } if(questState.error) { if(!questState.beQuiet) { int retry=0; if((durable)&&(resetData==null)) retry=10; else if(resetData!=null) retry=resetData[0]; Log.errOut("Quest","Errors starting '" +name() +"', quest not started" +((retry>0)?", retry in "+retry+".":".")); } if((durable)&&(resetData==null)) { resetQuest(10); return false; } CMLib.coffeeTables().bump(this,CoffeeTableRow.STAT_QUESTFAILEDSTART); } else if(!questState.done) Log.errOut("Quest","Nothing parsed in '"+name()+"', quest not started."); else if(duration()<0) { Log.errOut("Quest","No duration, quest '"+name()+"' not started."); questState.error=true; } if((!questState.error)&&(questState.done)) { enterRunningState(); return true; } stopQuestInternal(); return false; } public void enterRunningState() { if(duration()>=0) { waitRemaining=-1; if(duration()==0) ticksRemaining=1; else if((resetData!=null)&&(resetData[1]>0)) ticksRemaining=resetData[1]; else ticksRemaining=duration(); CMLib.threads().startTickDown(this,Tickable.TICKID_QUEST,1); } resetData=null; lastStartDateTime=System.currentTimeMillis(); stepEllapsedTimes.remove(script()); } public void cleanQuestStep() { stoppingQuest=true; if(questState.worldObjects.size()>0) { synchronized(questState) { Enumeration<PreservedQuestObject> e; PreservedQuestObject PO; for(e=new ReverseEnumeration<PreservedQuestObject>(questState.worldObjects);e.hasMoreElements();) { PO=e.nextElement(); if(PO.preserveState>0) { PO.preserveState--; continue; } final PhysicalAgent P=PO.obj; final Ability A=P.fetchEffect("QuestBound"); if(A!=null) P.delEffect(A); questState.worldObjects.remove(PO); if(P instanceof Item) { if((CMath.bset(P.basePhyStats().disposition(),PhyStats.IS_UNSAVABLE)) &&(!((Item)P).amDestroyed())) ((Item)P).destroy(); } else if(P instanceof MOB) { final MOB M=(MOB)P; final ScriptingEngine B=(ScriptingEngine)M.fetchBehavior("Scriptable"); if(B!=null) B.endQuest(M,M,name()); final Room R=M.getStartRoom(); if((R==null)||(CMath.bset(M.basePhyStats().disposition(),PhyStats.IS_UNSAVABLE))) { M.setFollowing(null); CMLib.tracking().wanderAway(M,true,false); if(M.location()!=null) M.location().delInhabitant(M); M.setLocation(null); M.destroy(); } else if((!M.amDead()) &&(!M.amDestroyed()) &&((M.location()!=R)||(!R.isInhabitant(M)))) { M.setFollowing(null); CMLib.tracking().wanderAway(M,false,true); } } } } if(questState.addons.size()>0) { synchronized(questState) { if(stoppingQuest) for(int i=questState.addons.size()-1;i>=0;i--) { try { final Integer I=(Integer)questState.addons.elementAt(i,2); if(I.intValue()>0) { questState.addons.setElementAt(i,2,Integer.valueOf(I.intValue()-1)); continue; } final List V=(List)questState.addons.elementAt(i,1); questState.addons.removeElementAt(i); if(V.size()<2) continue; final Environmental E=(Environmental)V.get(0); final Object O=V.get(1); if(O instanceof String) { final String stat=(String)O; final String parms=(String)V.get(2); if(CMStrings.contains(E.getStatCodes(),stat.toUpperCase().trim())) E.setStat(stat,parms); else if((E instanceof MOB)&&CMStrings.contains(((Physical)E).basePhyStats().getStatCodes(),stat.toUpperCase().trim())) { ((Physical)E).basePhyStats().setStat(stat.toUpperCase().trim(),parms); ((Physical)E).recoverPhyStats(); } else if((E instanceof MOB)&&(CMStrings.contains(CharStats.CODES.NAMES(),stat.toUpperCase().trim()))) { ((MOB)E).baseCharStats().setStat(CMParms.indexOf(CharStats.CODES.NAMES(),stat.toUpperCase().trim()),CMath.s_int(parms)); ((MOB)E).recoverCharStats(); } else if((E instanceof MOB)&&CMStrings.contains(((MOB)E).baseState().getStatCodes(),stat)) { ((MOB)E).baseState().setStat(stat,parms); ((MOB)E).recoverMaxState(); ((MOB)E).resetToMaxState(); } } else if(O instanceof Behavior) { if(E instanceof PhysicalAgent) { final PhysicalAgent BB=(PhysicalAgent)E; Behavior B=BB.fetchBehavior(((Behavior)O).ID()); if((E instanceof MOB)&&(B instanceof ScriptingEngine)) ((ScriptingEngine)B).endQuest((PhysicalAgent)E,(MOB)E,name()); if((V.size()>2)&&(V.get(2) instanceof String)) { if(B==null){ B=(Behavior)O; BB.addBehavior(B);} B.setParms((String)V.get(2)); } else if(B!=null) BB.delBehavior(B); } } else if(O instanceof ScriptingEngine) { final ScriptingEngine S=(ScriptingEngine)O; if((E instanceof MOB)&&(!S.isSavable())) { S.endQuest((MOB)E,(MOB)E,name()); ((MOB)E).delScript(S); } } else if(O instanceof Ability) { if((V.size()>2) &&(V.get(2) instanceof Ability) &&(E instanceof MOB)) { Ability A=((MOB)E).fetchAbility(((Ability)O).ID()); if((V.size()>3)&&(V.get(3) instanceof String)) { if(A==null){A=(Ability)O; ((MOB)E).addAbility(A);} A.setMiscText((String)V.get(3)); } else if(A!=null) ((MOB)E).delAbility(A); } else if(E instanceof Physical) { Ability A=((Physical)E).fetchEffect(((Ability)O).ID()); if((V.size()>2)&&(V.get(2) instanceof String)) { if(A==null){A=(Ability)O; ((Physical)E).addEffect(A);} A.setMiscText((String)V.get(2)); } else if(A!=null) { A.unInvoke(); ((Physical)E).delEffect(A); } } } else if(O instanceof Item) ((Item)O).destroy(); } catch(ArrayIndexOutOfBoundsException e) { // eat it } } } } } stoppingQuest=false; } // this will cause a quest to begin parsing its next "step". // this will clear out unpreserved objects from previous // step and resume quest script processing. // if this is the LAST step, stopQuestInternal() is automatically called @Override public boolean stepQuest() { if((questState==null)||(stoppingQuest)) return false; cleanQuestStep(); ticksRemaining=-1; setDuration(-1); final List args=new Vector(); final Vector script=parseLoadScripts(script(),new Vector(),args,true); try { setVars(script,questState.lastLine); parseQuestScript(script,args,questState.lastLine); } catch(final Exception t) { questState.error=true; Log.errOut("DefaultQuest",t); } if(questState.error) { if(!questState.beQuiet) Log.errOut("Quest","One or more errors in '"+name()+"', quest not started"); } else if(!questState.done) { // valid DONE state, when stepping over the end } else if(duration()<0) { Log.errOut("Quest","No duration, quest '"+name()+"' not started."); questState.error=true; } if((!questState.error)&&(questState.done)&&(duration()>=0)) { enterRunningState(); return true; } stopQuestInternal(); return false; } @Override public void resetQuest(int firstPauseTicks) { if(stoppingQuest) return; // ticksRemaining of -1 is OK, it will grab duration resetData=new int[]{firstPauseTicks,ticksRemaining}; stopQuest(); } @Override public void stopQuest() { if((!stoppingQuest)&&(running())) CMLib.coffeeTables().bump(this,CoffeeTableRow.STAT_QUESTSUCCESS); stopQuestInternal(); } // this will stop executing of the quest script. It will clean up // any objects or mobs which may have been loaded, restoring map // mobs to their previous state. public void stopQuestInternal() { if(stoppingQuest) return; // first set everything to complete! synchronized(questState) { for(final PreservedQuestObject PO : questState.worldObjects) PO.preserveState=0; for(int q=0;q<questState.addons.size();q++) questState.addons.setElementAt(q,2,Integer.valueOf(0)); questState.autoStepAfterDuration=false; } cleanQuestStep(); stoppingQuest=true; if(!isCopy()) setScript(script(),true); // causes wait times/name to reload enterDormantState(); stoppingQuest=false; } @Override public boolean enterDormantState() { ticksRemaining=-1; if((isCopy())||(!resetWaitRemaining(0))) { CMLib.quests().delQuest(this); CMLib.threads().deleteTick(this,Tickable.TICKID_QUEST); return false; } return true; } @Override public boolean resetWaitRemaining(long ellapsedTime) { if(resetData!=null) { waitRemaining=resetData[0]; resetData[0]*=2; return true; } if(((minWait()<0)||(maxWait<0)) &&(startDate().trim().length()==0)) return false; if(running()) return true; if(startDate().length()>0) { if(startDate().toUpperCase().startsWith("MUDDAY")) { final String sd2=startDate().substring("MUDDAY".length()).trim(); final int x=sd2.indexOf('-'); if(x<0) return false; final int mudmonth=CMath.s_parseIntExpression(sd2.substring(0,x)); final int mudday=CMath.s_parseIntExpression(sd2.substring(x+1)); final TimeClock C=(TimeClock)CMClass.getCommon("DefaultTimeClock"); final TimeClock NOW=CMLib.time().globalClock(); C.setMonth(mudmonth); C.setDayOfMonth(mudday); C.setHourOfDay(0); if((mudmonth<NOW.getMonth()) ||((mudmonth==NOW.getMonth())&&(mudday<NOW.getDayOfMonth()))) C.setYear(NOW.getYear()+1); else C.setYear(NOW.getYear()); final long distance=C.deriveMillisAfter(NOW); waitRemaining=(int)(distance/CMProps.getTickMillis()); } else { final int x=startDate.indexOf('-'); if(x<0) return false; final int month=CMath.s_parseIntExpression(startDate.substring(0,x)); final int day=CMath.s_parseIntExpression(startDate.substring(x+1)); int year=Calendar.getInstance().get(Calendar.YEAR); long distance=CMLib.time().string2Millis(month+"/"+day+"/"+year+" 12:00 AM"); final Calendar C=Calendar.getInstance(); long today=CMLib.time().string2Millis((C.get(Calendar.MONTH)+1)+"/"+C.get(Calendar.DAY_OF_MONTH)+"/"+C.get(Calendar.YEAR)+" 12:00 AM"); while(distance<today) distance=CMLib.time().string2Millis(month+"/"+day+"/"+(++year)+" 12:00 AM"); waitRemaining=(int)((distance-today)/CMProps.getTickMillis()); } } else waitRemaining=(minWait+(CMLib.dice().roll(1,maxWait,0)))-(int)(ellapsedTime/CMProps.getTickMillis()); return true; } @Override public int minWait() { return minWait; } @Override public void setMinWait(int wait) { minWait = wait; } @Override public int waitInterval() { return maxWait; } @Override public void setWaitInterval(int wait) { maxWait = wait; } @Override public int waitRemaining() { return waitRemaining; } public Quest getMainQuestObject() { Quest Q=this; if(isCopy()) { Quest Q2=null; for(int q=0;q<CMLib.quests().numQuests();q++) { Q2=CMLib.quests().fetchQuest(q); if((Q2!=null)&&(Q2.name().equals(name))&&(!isCopy())) { Q = Q2; break; } } } return Q; } // if the quest has a winner, this is him. @Override public void declareWinner(String name) { if(name==null) return; name=name.trim(); if(name.length()==0) return; final Quest Q=getMainQuestObject(); boolean wasWinner = false; boolean removeMe = false; if(name.startsWith("-")) { name=name.substring(1); removeMe=true; } final Map<String,Long> V=Q.getWinners(); if(V.remove(name) != null) { wasWinner = true; } if(removeMe) { if(wasWinner) { CMLib.database().DBUpdateQuest(Q); } } else { Q.getWinners().put(name,Long.valueOf(System.currentTimeMillis())); CMLib.database().DBUpdateQuest(Q); } } @Override public String getWinnerStr() { final Quest Q=getMainQuestObject(); final StringBuffer list=new StringBuffer(""); final Map<String,Long> V=Q.getWinners(); for(String name : V.keySet()) { final Long time=V.get(name); list.append(name+"@"+time.longValue()+";"); } return list.toString(); } @Override public void setWinners(String list) { final Quest Q=getMainQuestObject(); final Map<String,Long> V=Q.getWinners(); V.clear(); final List<String> parts=CMParms.parseSemicolons(list, true); for(String part : parts) { if(part.trim().length()>0) { final int x=part.indexOf('@'); Long time=Long.valueOf(0); String name=part.trim(); if(x>0) { name=part.substring(0,x).trim(); time=Long.valueOf(CMath.s_long(part.substring(x+1).trim())); } V.put(name,time); } } } // retreive the list of previous winners @Override public Map<String, Long> getWinners() { final Quest Q=getMainQuestObject(); if(Q==this) return winners; return Q.getWinners(); } // was a previous winner @Override public boolean wasWinner(final String name) { return whenLastWon(name) != null; } // was a previous winner @Override public Long whenLastWon(String name) { if(name==null) return null; name=name.trim(); if(name.length()==0) return null; final Quest Q=getMainQuestObject(); final Map<String,Long> V=Q.getWinners(); return V.get(name); } // informational @Override public boolean running() { return ticksRemaining >= 0; } @Override public boolean stopping() { return stoppingQuest; } @Override public boolean waiting() { return waitRemaining >= 0; } @Override public int ticksRemaining() { return ticksRemaining; } @Override public int minsRemaining() { return (int) (ticksRemaining * CMProps.getTickMillis() / 60000); } private int tickStatus = Tickable.STATUS_NOT; @Override public int getTickStatus() { return tickStatus; } @Override public boolean tick(Tickable ticking, int tickID) { if(tickID!=Tickable.TICKID_QUEST) return false; if(CMSecurity.isDisabled(CMSecurity.DisFlag.QUESTS) ||(CMProps.getBoolVar(CMProps.Bool.MUDSHUTTINGDOWN)) ||(!CMProps.getBoolVar(CMProps.Bool.MUDSTARTED)) ||(suspended())) return true; tickStatus=Tickable.STATUS_START; if(running()) { tickStatus=Tickable.STATUS_ALIVE; if(duration()>0) ticksRemaining--; if(ticksRemaining<0) { if((questState!=null)&&(questState.autoStepAfterDuration)) { stepQuest(); } else { CMLib.coffeeTables().bump(this,CoffeeTableRow.STAT_QUESTTIMESTOP); stopQuest(); } } tickStatus=Tickable.STATUS_END; } else { if(startQuestOnTime()) { CMLib.coffeeTables().bump(this,CoffeeTableRow.STAT_QUESTTIMESTART); } } tickStatus=Tickable.STATUS_NOT; return true; } protected boolean startQuestOnTime() { if((--waitRemaining)>=0) return false; boolean allowedToRun=true; if(runLevel()>=0) { for(int q=0;q<CMLib.quests().numQuests();q++) { final Quest Q=CMLib.quests().fetchQuest(q); if((!Q.name().equals(name)) &&(Q.running()) &&(Q.duration()!=0) &&(Q.runLevel()<=runLevel()) &&(Q.runLevel()>=0)) { allowedToRun = false; break; } } } if(allowedToRun) { int numElligiblePlayers=0; final boolean isMask=(playerMask.length()>0); for(final Session S : CMLib.sessions().localOnlineIterable()) { if((S.mob()!=null) &&((!isMask) || CMLib.masking().maskCheck(playerMask,S.mob(),true))) numElligiblePlayers++; } ticksRemaining=-1; if((numElligiblePlayers>=minPlayers)||(duration()==0)) return startQuestInternal(); } enterDormantState(); return false; } @Override public void runtimeRegisterAbility(MOB mob, String abilityID, String parms, boolean give) { if(mob==null) return; runtimeRegisterObject(mob); final Vector<Object> V=new Vector<Object>(); V.addElement(mob); Ability A4=mob.fetchAbility(abilityID); if(A4!=null) { V.addElement(A4); V.addElement(A4); V.addElement(A4.text()); if(give) { A4.setMiscText(parms); A4.setProficiency(100); } else mob.delAbility(A4); } else if(!give) return; else { A4=CMClass.getAbility(abilityID); if(A4==null) return; A4.setMiscText(parms); V.addElement(A4); V.addElement(A4); A4.setProficiency(100); mob.addAbility(A4); } synchronized(questState) { questState.addons.addElement(V,Integer.valueOf(questState.preserveState)); } } @Override public void runtimeRegisterObject(PhysicalAgent P) { synchronized(questState) { for(final PreservedQuestObject PO : questState.worldObjects) { if(PO.obj==P) { if(PO.preserveState<questState.preserveState) PO.preserveState=questState.preserveState; return; } } questState.worldObjects.add(new PreservedQuestObject(P,questState.preserveState)); final Ability A=CMClass.getAbility("QuestBound"); A.setMiscText(""+this); P.addNonUninvokableEffect(A); } } @Override public void runtimeRegisterEffect(PhysicalAgent affected, String abilityID, String parms, boolean give) { if(affected==null) return; runtimeRegisterObject(affected); final Vector<Object> V=new Vector<Object>(); V.addElement(affected); Ability A4=affected.fetchEffect(abilityID); if(A4!=null) { V.addElement(A4); V.addElement(A4.text()); if(give) { A4.makeLongLasting(); A4.setMiscText(parms); } else affected.delEffect(A4); } else if(!give) return; else { A4=CMClass.getAbility(abilityID); if(A4==null) return; V.addElement(A4); A4.setMiscText(parms); if(affected instanceof MOB) A4.startTickDown((MOB)affected,affected,99999); else A4.startTickDown(null,affected,99999); A4.makeLongLasting(); } synchronized(questState) { questState.addons.addElement(V,Integer.valueOf(questState.preserveState)); } } @Override public void runtimeRegisterBehavior(PhysicalAgent behaving, String behaviorID, String parms, boolean give) { if(behaving==null) return; runtimeRegisterObject(behaving); final Vector<Object> V=new Vector<Object>(); V.addElement(behaving); Behavior B=behaving.fetchBehavior(behaviorID); if(B!=null) { V.addElement(B); V.addElement(B.getParms()); if(give) B.setParms(parms); else behaving.delBehavior(B); } else if(!give) { return; } else { B=CMClass.getBehavior(behaviorID); if(B==null) return; V.addElement(B); B.setParms(parms); behaving.addBehavior(B); } B.registerDefaultQuest(name()); synchronized(questState) { questState.addons.addElement(V,Integer.valueOf(questState.preserveState)); } } public void runtimeRegisterStat(Environmental E, String stat, String parms, boolean give) { if(E==null) return; if(E instanceof PhysicalAgent) runtimeRegisterObject((PhysicalAgent)E); final Vector<Object> V=new Vector<Object>(); V.addElement(E); stat=stat.toUpperCase().trim(); String oldVal=""; if(CMStrings.contains(E.getStatCodes(),stat)) oldVal=E.getStat(stat); else if((E instanceof Physical)&&CMStrings.contains(((Physical)E).basePhyStats().getStatCodes(),stat)) oldVal=((Physical)E).basePhyStats().getStat(stat); else if((E instanceof MOB)&&(CMStrings.contains(CharStats.CODES.NAMES(),stat))) oldVal=""+((MOB)E).baseCharStats().getStat(CMParms.indexOf(CharStats.CODES.NAMES(),stat)); else if((E instanceof MOB)&&CMStrings.contains(((MOB)E).baseState().getStatCodes(),stat)) oldVal=((MOB)E).baseState().getStat(stat); V.addElement(stat); V.addElement(oldVal); if(!give) return; V.addElement(stat); V.addElement(oldVal); if(CMStrings.contains(E.getStatCodes(),stat)) E.setStat(stat,parms); else if((E instanceof Physical)&&CMStrings.contains(((Physical)E).basePhyStats().getStatCodes(),stat)) { ((Physical)E).basePhyStats().setStat(stat,parms); ((Physical)E).recoverPhyStats(); } else if((E instanceof MOB)&&(CMStrings.contains(CharStats.CODES.NAMES(),stat))) { ((MOB)E).baseCharStats().setStat(CMParms.indexOf(CharStats.CODES.NAMES(),stat),CMath.s_int(parms)); ((MOB)E).recoverCharStats(); } else if((E instanceof MOB)&&CMStrings.contains(((MOB)E).baseState().getStatCodes(),stat)) { ((MOB)E).baseState().setStat(stat,parms); ((MOB)E).recoverMaxState(); ((MOB)E).resetToMaxState(); } synchronized(questState) { questState.addons.addElement(V,Integer.valueOf(questState.preserveState)); } } public int getQuestThingIndex(Iterator<? extends Environmental> i, String name, CMClass.CMObjectType type, int[] num) { if(i==null) return -1; Environmental E; for(;i.hasNext();) { E=i.next(); if(CMClass.isType(E,type)) { switch(type) { case LOCALE: if(CMLib.map().getExtendedRoomID((Room)E).equalsIgnoreCase(name)) return num[0]; break; default: if(E.Name().equalsIgnoreCase(name)) return num[0]; break; } num[0]++; } } return -1; } @Override public int getQuestMobIndex(String name) { final int[] num={1}; int x=-1; synchronized(questState) { if(questState.worldObjects!=null) x=getQuestThingIndex(PreservedQuestObject.getPOIter(questState.worldObjects),name,CMClass.CMObjectType.MOB,num); if((x<0)&&(questState.mobGroup!=null)) x=getQuestThingIndex(questState.mobGroup.iterator(),name,CMClass.CMObjectType.MOB,num); if((x<0)&&(questState.mysteryData!=null)&&(questState.mysteryData.agentGroup!=null)) x=getQuestThingIndex(questState.mysteryData.agentGroup.iterator(),name,CMClass.CMObjectType.MOB,num); } return x; } @Override public int getQuestRoomIndex(String roomID) { final int[] num={1}; int x=-1; synchronized(questState) { if(questState.worldObjects!=null) x=getQuestThingIndex(PreservedQuestObject.getPOIter(questState.worldObjects),roomID,CMClass.CMObjectType.LOCALE,num); if((x<0)&&(questState.roomGroup!=null)) x=getQuestThingIndex(questState.roomGroup.iterator(),roomID,CMClass.CMObjectType.LOCALE,num); if(questState.mysteryData!=null) { if((x<0)&&(questState.mysteryData.whereAtGroup!=null)) x=getQuestThingIndex(questState.mysteryData.whereAtGroup.iterator(),roomID,CMClass.CMObjectType.LOCALE,num); if((x<0)&&(questState.mysteryData.whereHappenedGroup!=null)) x=getQuestThingIndex(questState.mysteryData.whereHappenedGroup.iterator(),roomID,CMClass.CMObjectType.LOCALE,num); } } return x; } @Override public int getQuestItemIndex(String name) { final int[] num={1}; int x=-1; synchronized(questState) { if(questState.worldObjects!=null) x=getQuestThingIndex(PreservedQuestObject.getPOIter(questState.worldObjects),name,CMClass.CMObjectType.ITEM,num); if((x<0)&&(questState.itemGroup!=null)) x=getQuestThingIndex(questState.itemGroup.iterator(),name,CMClass.CMObjectType.ITEM,num); if(questState.mysteryData!=null) { if((x<0)&&(questState.mysteryData.toolGroup!=null)) x=getQuestThingIndex(questState.mysteryData.toolGroup.iterator(),name,CMClass.CMObjectType.ITEM,num); } } return x; } @Override public long getFlags() { return suspended()?FLAG_SUSPENDED:0; } @Override public void setFlags(long flags) { if(CMath.bset(flags,FLAG_SUSPENDED)) { setSuspended(true); } } public Environmental getQuestThing(Iterator<? extends Environmental> e, int dex, CMClass.CMObjectType type, int[] num) { if(e==null) return null; Environmental E; for(;e.hasNext();) { E=e.next(); if(CMClass.isType(E,type)) { if(dex==num[0]) return E; num[0]++; } } return null; } @Override public MOB getQuestMob(int i) { final int[] num={1}; Environmental E=null; synchronized(questState) { if(questState.worldObjects!=null) E=getQuestThing(PreservedQuestObject.getPOIter(questState.worldObjects),i,CMClass.CMObjectType.MOB,num); if(E instanceof MOB) return (MOB)E; if(questState.mobGroup!=null) E=getQuestThing(questState.mobGroup.iterator(),i,CMClass.CMObjectType.MOB,num); if(E instanceof MOB) return (MOB)E; if((questState.mysteryData!=null)&&(questState.mysteryData.agentGroup!=null)) E=getQuestThing(questState.mysteryData.agentGroup.iterator(),i,CMClass.CMObjectType.MOB,num); if(E instanceof MOB) return (MOB)E; } return null; } @Override public Item getQuestItem(int i) { final int[] num={1}; Environmental E=null; synchronized(questState) { if(questState.worldObjects!=null) E=getQuestThing(PreservedQuestObject.getPOIter(questState.worldObjects),i,CMClass.CMObjectType.ITEM,num); if(E instanceof Item) return (Item)E; if(questState.itemGroup!=null) E=getQuestThing(questState.itemGroup.iterator(),i,CMClass.CMObjectType.ITEM,num); if(E instanceof Item) return (Item)E; if((questState.mysteryData!=null)&&(questState.mysteryData.toolGroup!=null)) E=getQuestThing(questState.mysteryData.toolGroup.iterator(),i,CMClass.CMObjectType.ITEM,num); if(E instanceof Item) return (Item)E; } return null; } @Override public Room getQuestRoom(int i) { final int[] num={1}; Environmental E=null; synchronized(questState) { if(questState.worldObjects!=null) E=getQuestThing(PreservedQuestObject.getPOIter(questState.worldObjects),i,CMClass.CMObjectType.LOCALE,num); if(E instanceof Room) return (Room)E; E=getQuestThing(questState.roomGroup.iterator(),i,CMClass.CMObjectType.LOCALE,num); if(E instanceof Room) return (Room)E; if((questState.mysteryData!=null)&&(questState.mysteryData.whereAtGroup!=null)) E=getQuestThing(questState.mysteryData.whereAtGroup.iterator(),i,CMClass.CMObjectType.LOCALE,num); if(E instanceof Room) return (Room)E; if((questState.mysteryData!=null)&&(questState.mysteryData.whereHappenedGroup!=null)) E=getQuestThing(questState.mysteryData.whereHappenedGroup.iterator(),i,CMClass.CMObjectType.LOCALE,num); if(E instanceof Room) return (Room)E; } return null; } @Override public String getQuestMobName(int i) { final MOB M=getQuestMob(i); if(M!=null) return M.name(); return ""; } @Override public String getQuestItemName(int i) { final Item I=getQuestItem(i); if(I!=null) return I.name(); return ""; } @Override public String getQuestRoomID(int i) { final Room R=getQuestRoom(i); if(R!=null) return CMLib.map().getExtendedRoomID(R); return ""; } @Override public int getObjectInUseIndex(String name) { synchronized(questState) { if(questState.worldObjects!=null) { for(int i=0;i<questState.worldObjects.size();i++) { final PhysicalAgent O=questState.worldObjects.get(i).obj; if(O.name().equalsIgnoreCase(name)) return (i+1); } } } return -1; } @Override public boolean isObjectInUse(Environmental E) { if((questState.worldObjects!=null)&&(E!=null)) { for(final PreservedQuestObject PO : questState.worldObjects) { if(PO.obj==E) return true; } } return false; } public Vector parseLoadScripts(String text, List oldArgs, List args, boolean showErrors) { final Vector script=new Vector(); if(text.trim().toUpperCase().startsWith("LOAD=")) { String filename=null; final Vector<String> V=CMParms.parse(text.trim().substring(5).trim()); if(V.size()>0) { filename=V.firstElement(); Vector<String> parms=null; try { for(int v=1;v<V.size();v++) { parms=CMParms.parse(V.elementAt(v)); final Object O=getObjectIfSpecified(parms,oldArgs,0,1); args.add((O==null)?"":O); } final StringBuffer buf=getResourceFileData(filename,showErrors); if(buf!=null) text=buf.toString(); } catch(final CMException ex) { Log.errOut("DefaultQuest","'"+text+"' either has a space in the filename, or unknown parms."); } } } final int x=text.toLowerCase().indexOf(XMLLibrary.FILE_XML_BOUNDARY.toLowerCase()); if(x>=0) { final String xml=text.substring(x+XMLLibrary.FILE_XML_BOUNDARY.length()).trim(); text=text.substring(0,x); if((xml.length()>0)&&(internalFiles==null)) { final List<XMLLibrary.XMLTag> topXMLV=CMLib.xml().parseAllXML(xml); for(int t=0;t<topXMLV.size();t++) { final XMLTag filePiece=topXMLV.get(t); String name=null; String data=null; if(filePiece.tag().equalsIgnoreCase("FILE")&&(filePiece.contents()!=null)) { for(int p=0;p<filePiece.contents().size();p++) { final XMLTag piece=filePiece.contents().get(p); if(piece.tag().equalsIgnoreCase("NAME")) name=piece.value(); if(piece.tag().equalsIgnoreCase("DATA")) data=piece.value(); } } if((name!=null)&&(data!=null)&&(name.trim().length()>0)&&(data.trim().length()>0)) { if(internalFiles==null) internalFiles=new DVector(2); internalFiles.addElement(name.toUpperCase().trim(),new StringBuffer(data)); } } } } Vector V=script; while(text.length()>0) { int y=-1; int yy=0; while(yy<text.length()) { if ((text.charAt(yy) == ';') && ((yy <= 0) || (text.charAt(yy - 1) != '\\'))) { y = yy; break; } else if (text.charAt(yy) == '\n') { y = yy; break; } else if (text.charAt(yy) == '\r') { y = yy; break; } else yy++; } String cmd=""; if(y<0) { cmd=text.trim(); text=""; } else { cmd=text.substring(0,y).trim(); text=text.substring(y+1).trim(); } if((cmd.length()>0)&&(!cmd.startsWith("#"))) { if(cmd.toUpperCase().startsWith("<OPTION>")) { V=new Vector(); script.addElement(V); } else if(cmd.toUpperCase().startsWith("</OPTION>")) V=script; else V.addElement(CMStrings.replaceAll(cmd,"\\;",";").trim()); } } return script; } private static final String VALID_ASTR_CODES="_&|"; private String modifyStringFromArgs(String s, List args) { int x=s.toUpperCase().indexOf('$'); while((x>=0)&&(x<s.length()-1)) { int y=x+1; if((y<s.length())&&(VALID_ASTR_CODES.indexOf(s.charAt(y))>=0)) y++; while((y<s.length())&&(Character.isLetterOrDigit(s.charAt(y)))) y++; try { String possObjName=(x+1>=y)?null:s.substring(x+1,y); if((possObjName!=null)&&(possObjName.length()>0)) { final char firstCode=possObjName.charAt(0); if(VALID_ASTR_CODES.indexOf(firstCode)>=0) possObjName=possObjName.substring(1); final Object O=getObjectIfSpecified(CMParms.cleanParameterList(possObjName),args,0,0); String replace=(O==null)?"null":O.toString(); if(O instanceof Room) replace=((Room)O).displayText(null); else if(O instanceof Environmental) replace=((Environmental)O).Name(); else if(O instanceof TimeClock) replace=((TimeClock)O).getShortTimeDescription(); switch(firstCode) { case '_': replace=CMStrings.capitalizeAndLower(replace); break; case '&': replace=CMLib.english().cleanArticles(replace); break; case '|': replace=CMLib.english().cleanArticles(replace).trim().replace(' ','|'); break; } s=s.substring(0,x)+replace+s.substring(y); } } catch (final CMException ex) { } x=s.toUpperCase().indexOf('$',x+1); } return s; } private Object getObjectIfSpecified(List<String> parms, List args, int startp, int object0vector1) throws CMException { if(parms.size()-startp==0) throw new CMException("Not specified"); final StringBuffer allParms=new StringBuffer(parms.get(startp)); for(int p=startp+1;p<parms.size();p++) allParms.append(parms.get(p)); Object O=null; final XVector V=new XVector(); int lastI=0; String eval=null; char code=' '; for(int i=0;i<=allParms.length();i++) { eval=null; if((i==allParms.length()) ||((i<allParms.length())&&((allParms.charAt(i)=='+')||(allParms.charAt(i)=='-')||(allParms.charAt(i)=='#')))) { eval=allParms.substring(lastI,i).trim().toUpperCase(); lastI=i+1; } if(eval!=null) { if(eval.startsWith("ARG")&&CMath.isMathExpression(eval.substring(3))) { final int num=CMath.parseIntExpression(eval.substring(3)); if((num<=0)||(num>args.size())) throw new CMException ("Not specified: "+eval); O=args.get(num-1); } else { if(!questState.isStat(eval)) throw new CMException ("Not specified: "+eval); O=questState.getStat(eval); } switch(code) { case '#': { int index=0; if(CMath.isMathExpression(eval)) index=CMath.parseIntExpression(eval); if((index>=0)&&(index<V.size())) { O=V.elementAt(index); V.clear(); V.addElement(O); } break; } case '-': if(O instanceof List) V.removeAll((List)O); else if(O!=null) V.removeElement(O); break; case '+': case ' ': if(O instanceof List) V.addAll((List)O); else if(O!=null) V.addElement(O); break; } if(i<allParms.length()) code=allParms.charAt(i); } } switch(object0vector1) { case 0: if(V.size()==0) return null; return V.elementAt(CMLib.dice().roll(1,V.size(),-1)); case 1: if(V.size()==0) return null; return V; } return null; } @Override public String[] getStatCodes() { final String[] CCODES=new String[QCODES.length+MYSTERY_QCODES.length]; for(int i=0;i<QCODES.length;i++) CCODES[i]=QCODES[i]; for(int i=0;i<MYSTERY_QCODES.length;i++) CCODES[QCODES.length+i]=MYSTERY_QCODES[i]; return QCODES; } @Override public int getSaveStatIndex() { return getStatCodes().length; } protected int getCodeNum(String code) { final String[] CCODES=getStatCodes(); for(int i=0;i<CCODES.length;i++) { if(code.equalsIgnoreCase(CCODES[i])) return i; } return -1; } public boolean sameAs(DefaultQuest E) { final String[] CCODES=getStatCodes(); for(int i=0;i<CCODES.length;i++) { if(!E.getStat(CCODES[i]).equals(getStat(CCODES[i]))) return false; } return true; } @Override public void setStat(String code, String val) { switch(getCodeNum(code)) { case 0: break; case 1: setName(val); break; case 2: setDuration(CMLib.time().parseTickExpression(val)); break; case 3: setMinWait(CMLib.time().parseTickExpression(val)); break; case 4: setMinPlayers(CMath.s_parseIntExpression(val)); break; case 5: setPlayerMask(val); break; case 6: setRunLevel(CMath.s_parseIntExpression(val)); break; case 7: setStartDate(val); break; case 8: setStartMudDate(val); break; case 9: setWaitInterval(CMLib.time().parseTickExpression(val)); break; case 10: setSpawn(CMParms.indexOf(SPAWN_DESCS, val.toUpperCase().trim())); break; case 11: setDisplayName(val); break; case 13: durable = CMath.s_bool(val); break; case 14: author = val; break; case 12: // instructions can and should fall through the default default: if((code.toUpperCase().trim().equalsIgnoreCase("REMAINING"))&&(running())) ticksRemaining=CMLib.time().parseTickExpression(val); else questState.vars.put(code.toUpperCase().trim(), val); break; } } @Override public boolean isStat(String code) { if((getCodeNum(code)>=0) ||(questState.vars.containsKey(code))) return true; return false; } @Override public String getStat(String code) { switch(getCodeNum(code)) { case 0: return "" + ID(); case 1: return "" + name(); case 2: return "" + duration(); case 3: return "" + minWait(); case 4: return "" + minPlayers(); case 5: return "" + playerMask(); case 6: return "" + runLevel(); case 7: return "" + startDate(); case 8: return "" + startDate(); case 9: return "" + waitInterval(); case 10: return SPAWN_DESCS[getSpawn()]; case 11: return displayName(); case 13: return Boolean.toString(durable); case 14: return author(); case 12: // instructions can and should fall through the default default: { code=code.toUpperCase().trim(); if((code.equalsIgnoreCase("REMAINING"))&&(running())) return ""+ticksRemaining; if(questState.vars.containsKey(code)) return questState.vars.get(code); if(questState.isStat(code)) { final Object O=questState.getStat(code); if(O instanceof Room) return ((Room)O).displayText(null); if(O instanceof TimeClock) return ((TimeClock)O).getShortTimeDescription(); if(O instanceof Environmental) return ((Environmental)O).Name(); if(O instanceof List) return ""+((List)O).size(); if(O!=null) return O.toString(); } else if(code.endsWith("_ROOMID")&&(questState.isStat(code.substring(0,code.length()-7)))) { code=code.substring(0,code.length()-7); Object O=questState.getStat(code); if(O instanceof List) { if(((List)O).size()>0) O=((List)O).get(CMLib.dice().roll(1,((List)O).size(),-1)); } if(O instanceof Environmental) { final Room R=CMLib.map().roomLocation((Environmental)O); if(R!=null) return CMLib.map().getExtendedRoomID(R); } } else if(code.endsWith("_CLASS")&&(questState.isStat(code.substring(0,code.length()-6)))) { code=code.substring(0,code.length()-6); Object O=questState.getStat(code); if(O instanceof List) { if(((List)O).size()>0) O=((List)O).get(CMLib.dice().roll(1,((List)O).size(),-1)); } if(O instanceof CMObject) return ((CMObject)O).ID(); else if(O!=null) return O.getClass().getName(); } return ""; } } } @Override public int compareTo(CMObject o) { return CMClass.classID(this).compareToIgnoreCase(CMClass.classID(o)); } /** * Objects selected for use by a quest can be preserved or released from * quest-state to quest-state. This object maps a world object in use * to its quest-states remaining. * @author Bo Zimmermanimmerman */ public static class PreservedQuestObject { public int preserveState; public PhysicalAgent obj; private static Converter<PreservedQuestObject, PhysicalAgent> converter = new Converter<PreservedQuestObject, PhysicalAgent>() { @Override public PhysicalAgent convert(PreservedQuestObject obj) { return obj.obj; } }; public PreservedQuestObject(PhysicalAgent o, int state) { this.obj = o; this.preserveState = state; } public static Iterator<PhysicalAgent> getPOIter(List<PreservedQuestObject> o) { final ConvertingIterator<PreservedQuestObject,PhysicalAgent> iter = new ConvertingIterator<PreservedQuestObject,PhysicalAgent>(o.iterator(),converter); return iter; } } /** * A quest state class maps the parse-state of a quest, since quest parsing * is highly state dependent, but the state is not explicit in the script itself. * @author Bo Zimmermanimmerman * */ public static class QuestState implements Cloneable { public MysteryData mysteryData = new MysteryData(); public List<MOB> loadedMobs = new Vector<MOB>(); public List<Item> loadedItems = new Vector<Item>(); public Area area = null; public Room room = null; public MOB mob = null; public List<MOB> mobGroup = null; public List<Item> itemGroup = null; public List<Room> roomGroup = null; public Item item = null; public Object envObject = null; public boolean error = false; public boolean done = false; public boolean beQuiet = false; public boolean autoStepAfterDuration = false; public int preserveState = 0; public int lastLine = 0; public int startLine; // contains a set of vectors, vectors are formatted as such: // key 1=vector, below. key 2=preserveState // 0=environmental item/mob/etc // 1=Ability, 2=Ability (for an ability added) // 1=Ability, 2=Ability, 3=String (for an ability modified) // 1=Effect(for an Effect added) // 1=Effect, 2=String (for an Effect modified) // 1=Behavior (for an Behavior added) // 1=Behavior, 2=String (for an Behavior modified) public DVector addons = new DVector(2); public Map<String, String> vars = new STreeMap<String, String>(); public List<PhysicalAgent> reselectable = new Vector<PhysicalAgent>(); public List<PreservedQuestObject> worldObjects = new SVector<PreservedQuestObject>(); public boolean isStat(String statName) { final int x=statName.indexOf('#'); if(x>=0) statName=statName.substring(0,x); for (final String element : QOBJS) if(statName.equalsIgnoreCase(element)) return true; if(mysteryData!=null) return mysteryData.isStat(statName); return false; } public Object getStat(String statName) { final int x=statName.indexOf('#'); String whichStr=null; int whichNum=-1; if(x>=0) { whichStr=statName.substring(x+1); if(whichStr.length()>0) whichNum=CMath.s_parseIntExpression(whichStr); statName=statName.substring(0,x); } Object O=null; int code=-1; for(int i=0;i<QOBJS.length;i++) if(statName.equalsIgnoreCase(QOBJS[i])) { code=i; break;} switch(code) { case 0: O = loadedMobs; break; case 1: O = loadedItems; break; case 2: O = area; break; case 3: O = room; break; case 4: O = mobGroup; break; case 5: O = itemGroup; break; case 6: O = roomGroup; break; case 7: O = item; break; case 8: O = envObject; break; case 9: O = new ConvertingList<PreservedQuestObject, PhysicalAgent>(worldObjects, PreservedQuestObject.converter); break; case 10: O = mob; break; default: if(mysteryData!=null) O=mysteryData.getStat(statName); break; } if(O instanceof List) { final List V=(List)O; if((whichStr!=null)&&((whichNum<=0)||(whichNum>V.size()))) return ""+V.size(); if(whichStr!=null) return V.get(whichNum-1); } return O; } } /** * MysteryData is a helper class for QuestState that stores quest * state variables for the parsing of quests that make use of the * "mystery" variables (mystery as in Sherlock Holmes, not as in * unknown). * @author Bo Zimmermanimmerman */ public static class MysteryData implements Cloneable { public List<Faction> factionGroup; public Faction faction; public MOB agent; public List<MOB> agentGroup; public Environmental target; public List<Environmental> targetGroup; public Environmental tool; public List<Environmental> toolGroup; public Room whereHappened; public List<Room> whereHappenedGroup; public Room whereAt; public List<Room> whereAtGroup; public String action; public List<String> actionGroup; public String motive; public List<String> motiveGroup; public TimeClock whenHappened; public List<TimeClock> whenHappenedGroup; public TimeClock whenAt; public List<TimeClock> whenAtGroup; public boolean isStat(String statName) { for (final String element : MYSTERY_QCODES) if(statName.equalsIgnoreCase(element)) return true; return false; } public Object getStat(String statName) { int code=-1; for(int i=0;i<MYSTERY_QCODES.length;i++) { if(statName.equalsIgnoreCase(MYSTERY_QCODES[i])) { code = i; break; } } switch(code) { case 0: return faction; case 1: return factionGroup; case 2: return agent; case 3: return agentGroup; case 4: return action; case 5: return actionGroup; case 6: return target; case 7: return targetGroup; case 8: return motive; case 9: return motiveGroup; case 10: return whereHappened; case 11: return whereHappenedGroup; case 12: return whereAt; case 13: return whereAtGroup; case 14: return whenHappened; case 15: return whenHappenedGroup; case 16: return whenAt; case 17: return whenAtGroup; case 18: return tool; case 19: return toolGroup; } return null; } } protected static class JScriptQuest extends ScriptableObject { @Override public String getClassName() { return "JScriptQuest"; } static final long serialVersionUID = 44; Quest quest = null; QuestState state = null; public Quest quest() { return quest; } public QuestState setupState() { return state; } public JScriptQuest(Quest Q, QuestState S) { quest = Q; state = S; } public static String[] functions = { "quest", "setupState", "toJavaString" }; public String toJavaString(Object O) { return Context.toString(O); } } }