@Override
	public void modifyFaction(MOB mob, Faction me) throws IOException
	{
		if(mob.isMonster())
			return;
		boolean ok=false;
		int showFlag=-1;
		if(CMProps.getIntVar(CMProps.Int.EDITORTYPE)>0)
			showFlag=-999;
		while((mob.session()!=null)&&(!mob.session().isStopped())&&(!ok))
		{
			int showNumber=0;
			// name
			me.setName(CMLib.genEd().prompt(mob,me.name(),++showNumber,showFlag,L("Name")));

			// ranges
			++showNumber;
			if(!me.ranges().hasMoreElements())
				me.addRange("0;100;Sample Range;SAMPLE;");
			while((mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				final StringBuffer list=new StringBuffer(showNumber+". Faction Division/Ranges List:\n\r");
				list.append(CMStrings.padRight(L("   Code"),16)+CMStrings.padRight(L("Name"),21)+CMStrings.padRight(L("Min"),11)+CMStrings.padRight(L("Max"),11)+CMStrings.padRight(L("Align"),6)+"\n\r");
				for(final Enumeration<FRange> e=me.ranges();e.hasMoreElements();)
				{
					final Faction.FRange FR=e.nextElement();
					list.append(CMStrings.padRight("   "+FR.codeName(),15)+" ");
					list.append(CMStrings.padRight(FR.name(),20)+" ");
					list.append(CMStrings.padRight(""+FR.low(),10)+" ");
					list.append(CMStrings.padRight(""+FR.high(),10)+" ");
					list.append(CMStrings.padRight(FR.alignEquiv().toString(),5)+"\n\r");
				}
				mob.tell(list.toString());
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				String which=mob.session().prompt(L("Enter a CODE to add, remove, or modify:"),"");
				if(which.length()==0)
					break;
				which=which.trim().toUpperCase();
				if(which.indexOf(' ')>=0)
				{
					mob.tell(L("Faction Range code names may not contain spaces."));
					break;
				}
				Faction.FRange FR=me.fetchRange(which);
				if(FR==null)
				{
					if(mob.session().confirm(L("Create a new range code named '@x1' (y/N): ",which),"N"))
					{
						FR=me.addRange("0;100;Change My Name;"+which+";");
					}
				}
				else
				if(mob.session().choose(L("Would you like to M)odify or D)elete this range (M/d): "),"MD","M").toUpperCase().startsWith("D"))
				{
					me.delRange(FR);
					mob.tell(L("Range deleted."));
					FR=null;
				}
				if(FR!=null)
				{
					String newName=mob.session().prompt(L("Enter a new name (@x1)\n\r: ",FR.name()),FR.name());
					boolean error99=false;
					if(newName.length()==0)
						error99=true;
					else
					for(final Enumeration<FRange> e=me.ranges();e.hasMoreElements();)
					{
						final Faction.FRange FR3=e.nextElement();
						if(FR3.name().equalsIgnoreCase(FR.name())&&(FR3!=FR))
						{
							mob.tell(L("A range already exists with that name!"));
							error99=true;
							break;
						}
					}
					if(error99)
						mob.tell(L("(no change)"));
					else
						FR.setName(newName);
					newName=mob.session().prompt(L("Enter the low end of the range (@x1)\n\r: ",""+FR.low()),""+FR.low());
					if(!CMath.isInteger(newName))
						mob.tell(L("(no change)"));
					else
						FR.setLow(CMath.s_int(newName));
					newName=mob.session().prompt(L("Enter the high end of the range (@x1)\n\r: ",""+FR.high()),""+FR.high());
					if((!CMath.isInteger(newName))||(CMath.s_int(newName)<FR.low()))
						mob.tell(L("(no change)"));
					else
						FR.setHigh(CMath.s_int(newName));
					final StringBuffer prompt=new StringBuffer("Select the 'virtue' (if any) of this range:\n\r");
					final StringBuffer choices=new StringBuffer("");
					for(final Faction.Align i : Faction.Align.values())
					{
						choices.append(""+i.ordinal());
						if(i==Faction.Align.INDIFF)
							prompt.append(i.ordinal()+") Not applicable\n\r");
						else
							prompt.append(i.ordinal()+") "+i.toString().toLowerCase()+"\n\r");
					}
					FR.setAlignEquiv(Faction.Align.values()[CMath.s_int(mob.session().choose(L("@x1Enter alignment equivalency or 0: ",prompt.toString()),choices.toString(),""+FR.alignEquiv().ordinal()))]);
				}
			}

			// show in score
			me.setShowInScore(CMLib.genEd().prompt(mob,me.showInScore(),++showNumber,showFlag,L("Show in 'Score'")));

			// show in factions
			me.setShowInFactionsCommand(CMLib.genEd().prompt(mob,me.showInFactionsCommand(),++showNumber,showFlag,L("Show in 'Factions' command")));

			// show in special reports
			boolean alreadyReporter=false;
			for(final Enumeration<Faction> e=CMLib.factions().factions();e.hasMoreElements();)
			{
				final Faction F2=e.nextElement();
				if(F2.showInSpecialReported())
					alreadyReporter=true;
			}
			if(!alreadyReporter)
				me.setShowInSpecialReported(CMLib.genEd().prompt(mob,me.showInSpecialReported(),++showNumber,showFlag,L("Show in Reports")));

			// show in editor
			me.setShowInEditor(CMLib.genEd().prompt(mob,me.showInEditor(),++showNumber,showFlag,L("Show in MOB Editor")));

			// auto defaults
			boolean error=true;
			me.setAutoDefaults(CMParms.parseSemicolons(CMLib.genEd().prompt(mob,CMParms.toSemicolonListString(me.autoDefaults()),++showNumber,showFlag,L("Optional automatic assigned values with zapper masks (semicolon delimited).\n\r    ")),true));

			// non-auto defaults
			error=true;
			if(!me.defaults().hasMoreElements())
				me.setDefaults(new XVector<String>("0"));
			++showNumber;
			while(error&&(mob.session()!=null)&&(!mob.session().isStopped()))
			{
				error=false;
				final String newDefaults=CMLib.genEd().prompt(mob,CMParms.toSemicolonListString(me.defaults()),showNumber,showFlag,L("Other default values with zapper masks (semicolon delimited).\n\r    "));
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				final List<String> V=CMParms.parseSemicolons(newDefaults,true);
				if(V.size()==0)
				{
					mob.tell(L("This field may not be empty."));
					error=true;
				}
				me.setDefaults(CMParms.parseSemicolons(newDefaults,true));
			}

			// choices and choice intro
			me.setChoices(CMParms.parseSemicolons(CMLib.genEd().prompt(mob,CMParms.toSemicolonListString(me.choices()),++showNumber,showFlag,L("Optional new player value choices (semicolon-delimited).\n\r    ")),true));
			if(me.choices().hasMoreElements())
				me.setChoiceIntro(CMLib.genEd().prompt(mob,me.choiceIntro(),++showNumber,showFlag,L("Optional choices introduction text. Filename")));

			// rate modifier
			final String newModifier=CMLib.genEd().prompt(mob,CMath.toPct(me.rateModifier()),++showNumber,showFlag,L("Rate modifier"));
			if((CMath.isNumber(newModifier))||(CMath.isPct(newModifier)))
				me.setRateModifier(CMath.s_pct(newModifier));

			// experience flag
			boolean error2=true;
			++showNumber;
			while(error2&&(mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				error2=false;
				final StringBuffer nextPrompt=new StringBuffer("\n\r");
				int myval=-1;
				for(int i=0;i<Faction.EXPAFFECT_NAMES.length;i++)
				{
					if(me.experienceFlag().equalsIgnoreCase(Faction.EXPAFFECT_NAMES[i]))
						myval=i;
					nextPrompt.append("  "+(i+1)+") "+CMStrings.capitalizeAndLower(Faction.EXPAFFECT_NAMES[i].toLowerCase())+"\n\r");
				}
				if(myval<0)
				{
					me.setExperienceFlag("NONE");
					myval=0;
				}
				if((showFlag!=showNumber)&&(showFlag>-999))
				{
					mob.tell(L("@x1. Affect on experience: @x2",""+showNumber,Faction.EXPAFFECT_NAMES[myval]));
					break;
				}
				final String prompt="Affect on experience:  "+Faction.EXPAFFECT_NAMES[myval]+nextPrompt.toString()+"\n\rSelect a value: ";
				final int mynewval=CMLib.genEd().prompt(mob,myval+1,showNumber,showFlag,prompt);
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				if((mynewval<=0)||(mynewval>Faction.EXPAFFECT_NAMES.length))
				{
					mob.tell(L("That value is not valid."));
					error2=true;
				}
				else
					me.setExperienceFlag(Faction.EXPAFFECT_NAMES[mynewval-1]);
			}

			// factors by mask
			++showNumber;
			while((mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				final StringBuffer list=new StringBuffer(showNumber+". Faction change adjustment Factors with Zapper Masks:\n\r");
				list.append("    #) "+CMStrings.padRight(L("Zapper Mask"),31)+CMStrings.padRight(L("Gain"),6)+CMStrings.padRight(L("Loss"),6)+"\n\r");
				final StringBuffer choices=new StringBuffer("");
				int numFactors=0;
				for(final Enumeration<Faction.FZapFactor> e=me.factors();e.hasMoreElements();)
				{
					final Faction.FZapFactor factor=e.nextElement();
					choices.append(((char)('A'+numFactors)));
					list.append("    "+(((char)('A'+numFactors))+") "));
					list.append(CMStrings.padRight(factor.MOBMask(),30)+" ");
					list.append(CMStrings.padRight(""+CMath.toPct(factor.gainFactor()),5)+" ");
					list.append(CMStrings.padRight(""+CMath.toPct(factor.lossFactor()),5)+"\n\r");
					numFactors++;
				}
				mob.tell(list.toString());
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				final String which=mob.session().choose(L("Enter a # to remove, or modify, or enter 0 to Add:"),"0"+choices.toString(),"").trim().toUpperCase();
				final int factorNum=choices.toString().indexOf(which);
				if((which.length()!=1)
				||((!which.equalsIgnoreCase("0"))
					&&((factorNum<0)||(factorNum>=numFactors))))
					break;
				Faction.FZapFactor factor=null;
				if(!which.equalsIgnoreCase("0"))
				{
					factor=me.getFactor(factorNum);
					if(factor!=null)
					{
						if(mob.session().choose(L("Would you like to M)odify or D)elete this range (M/d): "),"MD","M").toUpperCase().startsWith("D"))
						{
							me.delFactor(factor);
							mob.tell(L("Factor deleted."));
							factor=null;
						}
					}
				}
				else
					factor=me.addFactor(1.0,1.0,"");
				if(factor!=null)
				{
					final String mask=mob.session().prompt(L("Enter a new zapper mask (@x1)\n\r: ",factor.MOBMask()),factor.MOBMask());
					double newHigh=factor.gainFactor();
					String newName=mob.session().prompt(L("Enter gain adjustment (@x1): ",CMath.toPct(newHigh)),CMath.toPct(newHigh));
					if((!CMath.isNumber(newName))&&(!CMath.isPct(newName)))
						mob.tell(L("(no change)"));
					else
						newHigh=CMath.s_pct(newName);

					double newLow=factor.lossFactor();
					newName=mob.session().prompt(L("Enter loss adjustment (@x1): ",CMath.toPct(newLow)),CMath.toPct(newLow));
					if((!CMath.isNumber(newName))&&(!CMath.isPct(newName)))
						mob.tell(L("(no change)"));
					else
						newLow=CMath.s_pct(newName);
					me.delFactor(factor);
					factor=me.addFactor(newHigh,newLow,mask);
				}
			}

			// relations between factions
			++showNumber;
			while((mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				final StringBuffer list=new StringBuffer(showNumber+". Cross-Faction Relations:\n\r");
				list.append("    Faction"+CMStrings.padRight("",25)+"Percentage change\n\r");
				for(final Enumeration<String> e=me.relationFactions();e.hasMoreElements();)
				{
					final String key=e.nextElement();
					final double value=me.getRelation(key);
					final Faction F=CMLib.factions().getFaction(key);
					if(F!=null)
					{
						list.append("    "+CMStrings.padRight(F.name(),31)+" ");
						list.append(CMath.toPct(value));
						list.append("\n\r");
					}
				}
				mob.tell(list.toString());
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				final String which=mob.session().prompt(L("Enter a faction to add, remove, or modify relations:"),"");
				if(which.length()==0)
					break;
				Faction theF=null;
				for(final Enumeration<String> e=me.relationFactions();e.hasMoreElements();)
				{
					final String key=e.nextElement();
					final Faction F=CMLib.factions().getFaction(key);
					if((F!=null)&&(F.name().equalsIgnoreCase(which)))
						theF=F;
				}
				if(theF==null)
				{
					Faction possibleF=CMLib.factions().getFaction(which);
					if(possibleF==null)
						possibleF=CMLib.factions().getFactionByName(which);
					if(possibleF==null)
						mob.tell(L("'@x1' is not a valid faction.",which));
					else
					if(mob.session().confirm(L("Create a new relation for faction  '@x1' (y/N):",possibleF.name()),"N"))
					{
						theF=possibleF;
						me.addRelation(theF.factionID(),1.0);
					}
				}
				else
				if(mob.session().choose(L("Would you like to M)odify or D)elete this relation (M/d): "),"MD","M").toUpperCase().startsWith("D"))
				{
					me.delRelation(theF.factionID());
					mob.tell(L("Relation deleted."));
					theF=null;
				}
				if(theF!=null)
				{
					final String amount=CMath.toPct(me.getRelation(theF.factionID()));
					final String newName=mob.session().prompt(L("Enter a relation amount (@x1): ",amount),""+amount);
					if((!CMath.isNumber(newName))&&(!CMath.isPct(newName)))
						mob.tell(L("(no change)"));
					me.delRelation(theF.factionID());
					me.addRelation(theF.factionID(),CMath.s_pct(newName));
				}
			}

			// faction change triggers
			++showNumber;
			while((mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				final StringBuffer list=new StringBuffer(showNumber+". Faction Change Triggers:\n\r");
				list.append("    "+CMStrings.padRight(L("Type"),15)
						+" "+CMStrings.padRight(L("Direction"),10)
						+" "+CMStrings.padRight(L("Factor"),10)
						+" "+CMStrings.padRight(L("Flags"),20)
						+" Mask\n\r");
				int numChanges=0;
				final StringBuffer choices=new StringBuffer("");
				final Hashtable<Character,Faction.FactionChangeEvent> choicesHashed=new Hashtable<Character,Faction.FactionChangeEvent>();
				for(final Enumeration<String> e=me.changeEventKeys();e.hasMoreElements();)
				{
					final Faction.FactionChangeEvent[] CEs=me.getChangeEvents(e.nextElement());
					if(CEs!=null)
					{
						for (final FactionChangeEvent CE : CEs)
						{
							choices.append(((char)('A'+numChanges)));
							list.append(" "+(((char)('A'+numChanges))+") "));
							choicesHashed.put(Character.valueOf((char)('A'+numChanges)), CE);
							if(CE.triggerParameters().trim().length()==0)
								list.append(CMStrings.padRight(CE.eventID(),15)+" ");
							else
								list.append(CMStrings.padRight(CE.eventID()+":"+CE.triggerParameters(),15)+" ");
							list.append(CMStrings.padRight(Faction.FactionChangeEvent.CHANGE_DIRECTION_DESCS[CE.direction()],10)+" ");
							list.append(CMStrings.padRight(CMath.toPct(CE.factor()),10)+" ");
							list.append(CMStrings.padRight(CE.flagCache(),20)+" ");
							list.append(CE.targetZapper()+"\n\r");
							numChanges++;
						}
					}
				}
				mob.tell(list.toString());
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				String which=mob.session().prompt(L("Select an ID to add, remove, or modify:"),"");
				which=which.toUpperCase().trim();
				if(which.length()==0)
					break;
				Faction.FactionChangeEvent CE=(which.length()>0)?choicesHashed.get(Character.valueOf(which.charAt(0))):null;
				if(CE==null)
				{
					final String newID=mob.session().prompt(L("Enter a new change ID (?): ")).toUpperCase().trim();
					if(newID.length()==0)
						break;
					if(newID.equalsIgnoreCase("?"))
					{
						mob.tell(L("Valid triggers: \n\r@x1",me.ALL_CHANGE_EVENT_TYPES()));
						continue;
					}
					CE=me.createChangeEvent(newID);
					if(CE==null)
					{
						mob.tell(L("That ID is invalid.  Try '?'."));
						continue;
					}
					else
					if(!mob.session().confirm(L("Create a new trigger using ID '@x1' (y/N): ",newID),"N"))
					{
						me.delChangeEvent(CE);
						CE=null;
						break;
					}
				}
				else
				if(mob.session().choose(L("Would you like to M)odify or D)elete this trigger (M/d): "),"MD","M").toUpperCase().startsWith("D"))
				{
					me.delChangeEvent(CE);
					mob.tell(L("Trigger deleted."));
					CE=null;
				}

				if(CE!=null)
				{
					final String newFlags=mob.session().prompt(L("Trigger parms (@x1): ",CE.triggerParameters()),CE.triggerParameters());
					if((newFlags.length()==0)||(newFlags.equals(CE.triggerParameters())))
						mob.tell(L("(no change)"));
					else
						CE.setTriggerParameters(newFlags.trim());
				}
				if(CE!=null)
				{
					final StringBuffer directions=new StringBuffer("Valid directions:\n\r");
					final StringBuffer cmds=new StringBuffer("");
					for(int i=0;i<Faction.FactionChangeEvent.CHANGE_DIRECTION_DESCS.length;i++)
					{
						directions.append(((char)('A'+i))+") "+Faction.FactionChangeEvent.CHANGE_DIRECTION_DESCS[i]+"\n\r");
						cmds.append((char)('A'+i));
					}
					final String str=mob.session().choose(L("@x1\n\rSelect a new direction (@x2): ",directions.toString(),Faction.FactionChangeEvent.CHANGE_DIRECTION_DESCS[CE.direction()]),cmds.toString()+"\n\r","");
					if((str.length()==0)||str.equals("\n")||str.equals("\r")||(cmds.toString().indexOf(str.charAt(0))<0))
						mob.tell(L("(no change)"));
					else
						CE.setDirection((cmds.toString().indexOf(str.charAt(0))));
				}
				if(CE!=null)
				{
					if(CE.factor()==0.0)
						CE.setFactor(1.0);
					final String amount=CMath.toPct(CE.factor());
					final String newName=mob.session().prompt(L("Enter the amount factor (@x1): ",amount),""+amount);
					if((!CMath.isNumber(newName))&&(!CMath.isPct(newName)))
						mob.tell(L("(no change)"));
					else
						CE.setFactor(CMath.s_pct(newName));
				}
				if(CE!=null)
				{
					mob.tell(L("Valid flags include: @x1\n\r",CMParms.toListString(Faction.FactionChangeEvent.FLAG_DESCS)));
					final String newFlags=mob.session().prompt(L("Enter new flag(s) (@x1): @x2",CE.flagCache(),CE.flagCache()),CE.flagCache());
					if((newFlags.length()==0)||(newFlags.equals(CE.flagCache())))
						mob.tell(L("(no change)"));
					else
						CE.setFlags(newFlags);
				}
				if(CE!=null)
				{
					final String newFlags=mob.session().prompt(L("Zapper mask (@x1): @x2",CE.targetZapper(),CE.targetZapper()),CE.targetZapper());
					if((newFlags.length()==0)||(newFlags.equals(CE.targetZapper())))
						mob.tell(L("(no change)"));
					else
						CE.setTargetZapper(newFlags);
				}
			}

			// Ability allowances
			++showNumber;
			while((mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				if((showFlag>0)&&(showFlag!=showNumber))
					break;
				final StringBuffer list=new StringBuffer(showNumber+". Ability allowances:\n\r");
				list.append("    #) "
						+CMStrings.padRight(L("Ability masks"),40)
						+" "+CMStrings.padRight(L("Low value"),10)
						+" "+CMStrings.padRight(L("High value"),10)
						+"\n\r");
				int numUsages=0;
				final StringBuffer choices=new StringBuffer("0\n\r");
				for(final Enumeration<Faction.FAbilityUsage> e=me.abilityUsages();e.hasMoreElements();)
				{
					final Faction.FAbilityUsage CA=e.nextElement();
					if(CA!=null)
					{
						list.append("    "+((char)('A'+numUsages)+") "));
						list.append(CMStrings.padRight(CA.abilityFlags(),40)+" ");
						list.append(CMStrings.padRight(CA.low()+"",10)+" ");
						list.append(CMStrings.padRight(CA.high()+"",10)+" ");
						list.append("\n\r");
						choices.append((char)('A'+numUsages));
						numUsages++;
					}
				}
				mob.tell(list.toString());
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				String which=mob.session().choose(L("Select an allowance to remove or modify, or enter 0 to Add:"),choices.toString(),"");
				if(which.length()!=1)
					break;
				which=which.toUpperCase().trim();
				Faction.FAbilityUsage CA=null;
				if(!which.equalsIgnoreCase("0"))
				{
					final int num=(which.charAt(0)-'A');
					if((num<0)||(num>=numUsages))
						break;
					CA=me.getAbilityUsage(num);
					if(CA==null)
					{
						mob.tell(L("That allowance is invalid.."));
						continue;
					}
					if(mob.session().choose(L("Would you like to M)odify or D)elete this allowance (M/d): "),"MD","M").toUpperCase().startsWith("D"))
					{
						me.delAbilityUsage(CA);
						mob.tell(L("Allowance deleted."));
						CA=null;
					}
				}
				else
				if(!mob.session().confirm(L("Create a new allowance (y/N): "),"N"))
				{
					continue;
				}
				else
					CA=me.addAbilityUsage(null);
				if(CA!=null)
				{
					boolean cont=false;
					while((!cont)&&(!mob.session().isStopped()))
					{
						final String newFlags=mob.session().prompt(L("Ability determinate masks or ? (@x1): @x2",CA.abilityFlags(),CA.abilityFlags()),CA.abilityFlags());
						if(newFlags.equalsIgnoreCase("?"))
						{
							final StringBuffer vals=new StringBuffer("Valid masks: \n\r");
							for (final String element : Ability.ACODE_DESCS)
								vals.append(element+", ");
							for (final String element : Ability.DOMAIN_DESCS)
								vals.append(element+", ");
							for (final String element : Ability.FLAG_DESCS)
								vals.append(element+", ");
							vals.append(" * Any ABILITY ID (skill/prayer/spell/etc)");
							mob.tell(vals.toString());
							cont=false;
						}
						else
						{
							cont=true;
							if((newFlags.length()==0)||(newFlags.equals(CA.abilityFlags())))
								mob.tell(L("(no change)"));
							else
							{
								final List<String> unknowns=CA.setAbilityFlag(newFlags);
								if(unknowns.size()>0)
									for(int i=unknowns.size()-1;i>=0;i--)
										if(CMClass.getAbility(unknowns.get(i))!=null)
											unknowns.remove(i);
								if(unknowns.size()>0)
								{
									mob.tell(L("The following are unknown masks: '@x1'.  Please correct them.",CMParms.toListString(unknowns)));
									cont=false;
								}
							}
						}
					}
					String newName=mob.session().prompt(L("Enter the minimum value to use the ability (@x1): ",""+CA.low()),""+CA.low());
					if((!CMath.isInteger(newName))||(CA.low()==CMath.s_int(newName)))
						mob.tell(L("(no change)"));
					else
						CA.setLow(CMath.s_int(newName));
					newName=mob.session().prompt(L("Enter the maximum value to use the ability (@x1): ",""+CA.high()),""+CA.high());
					if((!CMath.isInteger(newName))||(CA.high()==CMath.s_int(newName)))
						mob.tell(L("(no change)"));
					else
						CA.setHigh(CMath.s_int(newName));
					if(CA.high()<CA.low())
						CA.setHigh(CA.low());
				}
			}


			// Affects/Behaviors
			++showNumber;
			while((mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				if((showFlag>0)&&(showFlag!=showNumber))
					break;
				final StringBuffer list=new StringBuffer(showNumber+". Effects/Behaviors:\n\r");
				list.append("    #) "
						+CMStrings.padRight(L("Ability/Behavior ID"),25)
						+" "+CMStrings.padRight(L("MOB Mask"),20)
						+" "+CMStrings.padRight(L("Parameters"),20)
						+"\n\r");
				int numAffBehavs=0;
				final StringBuffer choices=new StringBuffer("0\n\r");
				final Vector<String> IDs=new Vector<String>();
				String ID=null;
				for(final Enumeration<String> e=me.affectsBehavs();e.hasMoreElements();)
				{
					ID=e.nextElement();
					final String[] parms=me.getAffectBehav(ID);
					list.append("    "+((char)('A'+numAffBehavs)+") "));
					list.append(CMStrings.padRight(ID,25)+" ");
					list.append(CMStrings.padRight(parms[1]+"",20)+" ");
					list.append(CMStrings.padRight(parms[0]+"",20)+" ");
					list.append("\n\r");
					choices.append((char)('A'+numAffBehavs));
					IDs.addElement(ID);
					numAffBehavs++;
				}
				mob.tell(list.toString());
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				String which=mob.session().choose(L("Select an ability/behavior ID to remove or modify, or enter 0 to Add:"),choices.toString(),"");
				if(which.length()!=1)
					break;
				which=which.toUpperCase().trim();
				if(!which.equalsIgnoreCase("0"))
				{
					final int num=(which.charAt(0)-'A');
					if((num<0)||(num>=IDs.size()))
						break;
					ID=IDs.elementAt(num);
					final String type=getWordAffOrBehav(ID);
					if(mob.session().choose(L("Would you like to M)odify or D)elete this @x1 (M/d): ",type),"MD","M").toUpperCase().startsWith("D"))
					{
						me.delAffectBehav(ID);
						mob.tell(L("@x1 deleted.",CMStrings.capitalizeAndLower(type)));
						ID=null;
					}
				}
				else
				{
					boolean cont=true;
					while((cont)&&(!mob.session().isStopped()))
					{
						cont=false;
						ID=mob.session().prompt(L("Enter a new Ability or Behavior ID or ?: "));
						if(ID.equalsIgnoreCase("?"))
						{
							final StringBuffer vals=new StringBuffer("Valid IDs: \n\r");
							vals.append(CMParms.toCMObjectListString(CMClass.abilities()));
							vals.append(CMParms.toCMObjectListString(CMClass.behaviors()));
							mob.tell(vals.toString());
							cont=true;
						}
						else
						{
							if((ID.length()==0)||(me.getAffectBehav(ID)!=null))
							{
								mob.tell(L("(nothing done)"));
								ID=null;
								break;
							}
							final String type=getWordAffOrBehav(ID);
							if(type==null)
							{
								mob.tell(L("'@x1 is neither a valid behavior ID or ability ID.  Use ? for a list.",ID));
								cont=true;
							}
							else
							if(!mob.session().confirm(L("Create a new @x1 (y/N): ",type),"N"))
							{
								ID=null;
								break;
							}
							else
								me.addAffectBehav(ID,"","");
						}
					}
				}
				if(ID!=null)
				{
					final String type=getWordAffOrBehav(ID);
					final String[] oldData=me.getAffectBehav(ID);
					final String[] newData=new String[2];
					boolean cont=true;
					while((cont)&&(!mob.session().isStopped()))
					{
						cont=false;
						final String mask=mob.session().prompt(L("Enter a new Zapper Mask or ? (@x1)\n\r: ",oldData[1]),oldData[1]);
						if(mask.equalsIgnoreCase("?"))
						{
							mob.tell(CMLib.masking().maskHelp("\n\r","disallow"));
							cont=true;
						}
						else
						if(!mask.equals(oldData[1]))
							newData[1]=mask;
					}

					cont=true;
					while((cont)&&(!mob.session().isStopped()))
					{
						cont=false;
						final String parms=mob.session().prompt(L("Enter new @x1 parameters for @x2 or ? (@x3)\n\r: ",type,ID,oldData[0]),oldData[0]);
						if(parms.equalsIgnoreCase("?"))
						{
							mob.tell(CMLib.help().getHelpText(ID,mob,true).toString());
							cont=true;
						}
						else
							if(!parms.equals(oldData[0]))
								newData[0]=parms;
					}
					if((newData[0]==null)&&(newData[1]!=null))
						newData[0]=oldData[0];
					else
					if((newData[0]!=null)&&(newData[1]==null))
						newData[1]=oldData[1];
					if((newData[0]!=null)&&(newData[1]!=null))
					{
						me.delAffectBehav(ID);
						me.addAffectBehav(ID,newData[0],newData[1]);
					}
				}
			}

			// Reaction Command/Affects/Behaviors
			++showNumber;
			while((mob.session()!=null)&&(!mob.session().isStopped())&&(!((showFlag>0)&&(showFlag!=showNumber))))
			{
				if((showFlag>0)&&(showFlag!=showNumber))
					break;
				final StringBuffer list=new StringBuffer(showNumber+". Reaction Commands/Effects/Behaviors:\n\r");
				list.append("    #) "
						+CMStrings.padRight(L("Range"),15)
						+" "+CMStrings.padRight(L("MOB Mask"),18)
						+" "+CMStrings.padRight(L("Able/Beh/Cmd"),15)
						+" "+CMStrings.padRight(L("Parameters"),18)
						+"\n\r");
				int numReactions=0;
				final StringBuffer choices=new StringBuffer("0\n\r");
				final Vector<Faction.FReactionItem> reactions=new Vector<Faction.FReactionItem>();
				Faction.FReactionItem item=null;
				for(final Enumeration<Faction.FReactionItem> e=me.reactions();e.hasMoreElements();)
				{
					item=e.nextElement();
					list.append("    "+((char)('A'+numReactions)+") "));
					list.append(CMStrings.padRight(item.rangeCodeName(),15)+" ");
					list.append(CMStrings.padRight(item.presentMOBMask()+"",18)+" ");
					list.append(CMStrings.padRight(item.reactionObjectID()+"",15)+" ");
					list.append(CMStrings.padRight(item.parameters()+"",18)+" ");
					list.append("\n\r");
					choices.append((char)('A'+numReactions));
					reactions.addElement(item);
					numReactions++;
				}
				mob.tell(list.toString());
				if((showFlag!=showNumber)&&(showFlag>-999))
					break;
				String which=mob.session().choose(L("Select one to remove or modify, or enter 0 to Add:"),choices.toString(),"");
				if(which.length()!=1)
					break;
				which=which.toUpperCase().trim();
				item=null;
				if(!which.equalsIgnoreCase("0"))
				{
					final int num=(which.charAt(0)-'A');
					if((num<0)||(num>=reactions.size()))
						break;
					item=reactions.elementAt(num);
					final String type=getWordAffOrBehav(item.reactionObjectID());
					if(mob.session().choose(L("Would you like to M)odify or D)elete this @x1 (M/d): ",type),"MD","M").toUpperCase().startsWith("D"))
					{
						me.delReaction(item);
						mob.tell(L("@x1 deleted.",CMStrings.capitalizeAndLower(type)));
						item=null;
					}
				}

				String type="";
				String[] oldData=new String[]{"","","",""};
				if(item != null)
				{
					type=getWordAffOrBehav(item.reactionObjectID());
					oldData=new String[]{item.rangeCodeName(),item.presentMOBMask(),item.reactionObjectID(),item.parameters()};
				}

				final String[] newData=new String[4];

				boolean cont=true;

				cont=true;
				while((cont)&&(!mob.session().isStopped()))
				{
					cont=false;

					final String rangeCode=mob.session().prompt(L("Enter a new range code or ? (@x1)\n\r: ",oldData[0]),oldData[0]).toUpperCase().trim();
					if(rangeCode.equalsIgnoreCase("?"))
					{
						final StringBuffer str=new StringBuffer("");
						for(final Enumeration<Faction.FRange> e=me.ranges();e.hasMoreElements();)
						{
							final Faction.FRange FR=e.nextElement();
							str.append(FR.codeName()+" ");
						}
						mob.tell(str.toString().trim()+"\n\r");
						cont=true;
					}
					else
					if(!rangeCode.equals(oldData[0]))
					{
						cont=true;
						for(final Enumeration<Faction.FRange> e=me.ranges();e.hasMoreElements();)
						{
							if(e.nextElement().codeName().equalsIgnoreCase(rangeCode))
							{
								newData[0]=rangeCode;
								cont=false;
							}
						}
						if(cont)
							mob.tell(L("'@x1' is not a valid range code.  Use ?",rangeCode));
					}
				}

				cont = true;
				while((cont)&&(!mob.session().isStopped()))
				{
					cont=false;

					final String mask=mob.session().prompt(L("Enter a new Zapper Mask or ? (@x1)\n\r: ",oldData[1]),oldData[1]);
					if(mask.equalsIgnoreCase("?"))
					{
						mob.tell(CMLib.masking().maskHelp("\n\r","disallow"));
						cont=true;
					}
					else
					if(!mask.equals(oldData[1]))
						newData[1]=mask;
				}

				cont=true;
				while((cont)&&(!mob.session().isStopped()))
				{
					cont=false;
					final String ID=mob.session().prompt(L("Enter a new Ability, Behavior, or Command ID (@x1)\n\r: ",oldData[2]),oldData[2]);
					if(ID.equalsIgnoreCase("?"))
					{
						final StringBuffer vals=new StringBuffer("Valid IDs: \n\r");
						vals.append(CMParms.toCMObjectListString(CMClass.abilities()));
						vals.append(CMParms.toCMObjectListString(CMClass.behaviors()));
						vals.append(CMParms.toCMObjectListString(CMClass.commands()));
						mob.tell(vals.toString());
						cont=true;
					}
					else
					{
						type=getWordAffOrBehav(ID);
						if(type==null)
						{
							mob.tell(L("'@x1 is neither a valid behavior, command, ability ID. Use ? for a list.",ID));
							cont=true;
						}
						else
							newData[2]=ID;
					}
				}

				cont=true;
				while((cont)&&(!mob.session().isStopped()))
				{
					cont=false;
					final String parms=mob.session().prompt(L("Enter new @x1 parameters for @x2 or ? (@x3)\n\r: ",type,newData[2],oldData[3]),oldData[3]);
					if(parms.equalsIgnoreCase("?"))
					{
						mob.tell(CMLib.help().getHelpText(newData[3],mob,true).toString());
						cont=true;
					}
					else
					if(!parms.equals(oldData[3]))
						newData[3]=parms;
				}

				for(int n=0;n<oldData.length;n++)
				{
					if(newData[n]==null)
						newData[n]=oldData[n];
				}
				if(item==null)
					me.addReaction(newData[0], newData[1], newData[2], newData[3]);
				else
				{
					item.setRangeName(newData[0]);
					item.setPresentMOBMask(newData[1]);
					item.setReactionObjectID(newData[2]);
					item.setParameters(newData[3]);
				}
			}
			if(me.reactions().hasMoreElements())
				me.setLightReactions(CMLib.genEd().prompt(mob,me.useLightReactions(),++showNumber,showFlag,L("Use 'Light' Reactions")));
			else
				me.setLightReactions(false);

			if(showFlag<-900)
			{
				ok=true;
				break;
			}
			if(showFlag>0)
			{
				showFlag=-1;
				continue;
			}
			showFlag=CMath.s_int(mob.session().prompt(L("Edit which? "),""));
			if(showFlag<=0)
			{
				showFlag=-1;
				ok=true;
			}
		}

		final String errMsg=resaveFaction(me);
		if(errMsg.length()>0)
			mob.tell(errMsg);
	}