/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Languages/
com/planet_ink/coffee_mud/Abilities/Misc/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Common/
com/planet_ink/coffee_mud/Common/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/CompTech/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Items/interfaces/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/
com/planet_ink/coffee_mud/core/collections/
com/planet_ink/coffee_mud/core/interfaces/
com/planet_ink/coffee_mud/core/intermud/
com/planet_ink/coffee_mud/core/intermud/i3/
com/planet_ink/coffee_web/server/
com/planet_ink/siplet/applet/
lib/
resources/factions/
resources/fakedb/
resources/progs/autoplayer/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/clan.templates/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
web/pub/textedit/
package com.planet_ink.coffee_mud.Abilities.Misc;
import com.planet_ink.coffee_mud.Abilities.StdAbility;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.core.collections.*;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Libraries.interfaces.*;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;

import java.util.*;

/*
   Copyright 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.
*/

public class Pregnancy extends StdAbility implements HealthCondition
{
	@Override
	public String ID()
	{
		return "Pregnancy";
	}

	private final static String	localizedName	= CMLib.lang().L("Pregnancy");

	@Override
	public String name()
	{
		return localizedName;
	}

	protected long	monthsRemaining	= -1;
	protected long	daysRemaining	= -1;

	@Override
	public String getHealthConditionDesc()
	{
		final int x=text().indexOf('/');
		if(x>0)
		{
			final TimeClock C=CMLib.time().localClock(affected);
			final int y=text().indexOf('/',x+1);
			if(y<0)
				return "";
			final long start=CMath.s_long(text().substring(0,x));
			final long divisor=CMProps.getTickMillis()*CMProps.getIntVar(CMProps.Int.TICKSPERMUDDAY);
			final long days=(System.currentTimeMillis()-start)/divisor; // down to days;
			final long months=days/C.getDaysInMonth();
			if(days<1)
				return "less than 1 day pregnant";
			else
			if(months<1)
				return days+" day(s) pregnant";
			else
				return months+" month(s) pregnant";
		}
		return "";
	}

	@Override
	public String displayText()
	{
		final String text=getHealthConditionDesc();
		if(text.length()>0)
			return "(is "+text+")";
		return "";
	}
	
	@Override
	protected int canAffectCode()
	{
		return CAN_MOBS;
	}

	@Override
	protected int canTargetCode()
	{
		return CAN_MOBS;
	}

	@Override
	public int abstractQuality()
	{
		return Ability.QUALITY_INDIFFERENT;
	}

	@Override
	public boolean putInCommandlist()
	{
		return false;
	}

	private static final String[]	triggerStrings	= I(new String[] { "IMPREGNATE" });

	@Override
	public String[] triggerStrings()
	{
		return triggerStrings;
	}

	@Override
	public boolean canBeUninvoked()
	{
		return false;
	}

	@Override
	public boolean isAutoInvoked()
	{
		return false;
	}

	@Override
	public boolean isSavable()
	{
		return true;
	}

	@Override
	public int classificationCode()
	{
		return Ability.ACODE_PROPERTY;
	}

	protected int	ticksInLabor	= 0;

	@Override
	public void executeMsg(Environmental host, CMMsg msg)
	{
		if((msg.target()==affected)
		&&((msg.targetMinor()==CMMsg.TYP_LOOK)||(msg.targetMinor()==CMMsg.TYP_EXAMINE))
		&&(CMLib.flags().canBeSeenBy(affected,msg.source()))
		&&(affected instanceof MOB)
		&&((daysRemaining>0)&&(monthsRemaining<=3)))
		{
			msg.addTrailerMsg(CMClass.getMsg(msg.source(),null,null,
										  CMMsg.MSG_OK_VISUAL,L("\n\r<S-NAME> <S-IS-ARE> obviously with child.\n\r"),
										  CMMsg.NO_EFFECT,null,
										  CMMsg.NO_EFFECT,null));
		}
		super.executeMsg(host,msg);
	}

	public Race getRace(MOB babe, String race1, String race2)
	{
		if(race1.indexOf(race2)>=0)
			return CMClass.getRace(race1);
		else
		if(race2.indexOf(race1)>=0)
			return CMClass.getRace(race2);

		Race R=null;
		if(race1.equalsIgnoreCase("Human")||race2.equalsIgnoreCase("Human"))
		{
			String halfRace=(race1.equalsIgnoreCase("Human")?race2:race1);
			R=CMClass.getRace(halfRace);
			if((R!=null)&&(!R.ID().toUpperCase().startsWith("HALF")))
			{
				halfRace="Half"+CMStrings.capitalizeAndLower(R.ID().toLowerCase());
				final Race testR=CMClass.getRace(halfRace);
				if(testR!=null)
					R=testR;
				else
				{
					R=R.mixRace(CMClass.getRace("Human"),halfRace,"Half "+CMStrings.capitalizeAndLower(R.name()));
					if(R.isGeneric() && (!R.ID().equals(race1))&& (!R.ID().equals(race2)))
					{
						CMClass.addRace(R);
						CMLib.database().DBCreateRace(R.ID(),R.racialParms());
					}
				}
			}
		}
		else
		if(race1.equalsIgnoreCase("Halfling")||race2.equalsIgnoreCase("Halfling"))
		{
			String halfRace=(race1.equalsIgnoreCase("Halfling")?race2:race1);
			R=CMClass.getRace(halfRace);
			if((R!=null)&&(!R.ID().endsWith("ling")))
			{
				halfRace=R.ID()+"ling";
				final Race testR=CMClass.getRace(halfRace);
				if(testR!=null)
					R=testR;
				else
				{
					R=R.mixRace(CMClass.getRace("Halfling"),halfRace,CMStrings.capitalizeAndLower(R.name())+"ling");
					if(R.isGeneric() && (!R.ID().equals(race1))&& (!R.ID().equals(race2)))
					{
						CMClass.addRace(R);
						CMLib.database().DBCreateRace(R.ID(),R.racialParms());
					}
				}
			}
		}
		else
		{
			String first=null;
			if(race1.length()==race2.length())
				first=(race1.compareToIgnoreCase(race2)<0)?race1:race2;
			else
			if(race1.length()>race2.length())
				first=race1;
			else
				first=race2;
			final String second=(first.equals(race1)?race2:race1);
			final String halfRace=(race1.compareToIgnoreCase(race2)<0)?race1+race2:race2+race1;
			final Race testR=CMClass.getRace(halfRace);
			final Race FIRSTR=CMClass.getRace(first);
			final Race SECONDR=CMClass.getRace(second);
			if(testR!=null)
				R=testR;
			else
			{
				R=FIRSTR.mixRace(SECONDR,halfRace,FIRSTR.name()+"-"+SECONDR.name());
				if(R.isGeneric() && (!R.ID().equals(race1))&& (!R.ID().equals(race2)))
				{
					CMClass.addRace(R);
					CMLib.database().DBCreateRace(R.ID(),R.racialParms());
				}
			}
		}
		return R;
	}


	@Override
	public boolean tick(Tickable ticking, int tickID)
	{
		if(!super.tick(ticking,tickID))
			return false;
		if((tickID==Tickable.TICKID_MOB)
		&&(affected instanceof MOB)
		&&(CMLib.flags().isInTheGame((MOB)affected,true)))
		{
			final MOB mob=(MOB)affected;
			final int x=text().indexOf('/');
			if(x>0)
			{
				final int y=text().indexOf('/',x+1);
				if(y>x)
				{
					final TimeClock C=CMLib.time().localClock(mob.getStartRoom());
					final int z=text().indexOf('/',y+1);
					final long end=CMath.s_long(text().substring(x+1,y));
					final long divisor=CMProps.getTickMillis()*CMProps.getIntVar(CMProps.Int.TICKSPERMUDDAY);
					daysRemaining=(end-System.currentTimeMillis())/divisor; // down to days
					monthsRemaining=daysRemaining/C.getDaysInMonth(); // down to months
					if(CMLib.dice().roll(1,200,0)==1)
					{
						final Ability A=CMClass.getAbility("Mood");
						if(A!=null)
							A.invoke(mob,new XVector<String>("RANDOM"),mob,true,0);
					}
					if(daysRemaining<7) // BIRTH!
					{
						if(CMLib.flags().isSleeping(mob))
							mob.enqueCommand(CMParms.parse("WAKE"),MUDCmdProcessor.METAFLAG_FORCED,0);
						if((CMLib.dice().rollPercentage()>50)&&(mob.charStats().getStat(CharStats.STAT_INTELLIGENCE)>5))
							mob.location().show(mob,null,CMMsg.MSG_NOISE,L("<S-NAME> moan(s) and scream(s) in labor pain!!"));
						ticksInLabor++;
						if(ticksInLabor>=45)
						{
							ticksInLabor=0;
							final String race1=mob.baseCharStats().getMyRace().ID();
							char gender='F';
							String sondat="daughter";
							final MOB babe=CMClass.getMOB("GenMOB");
							if(CMLib.dice().rollPercentage()>50)
							{
								gender='M';
								sondat="son";
							}
							String desc="The "+sondat+" of "+mob.Name();
							babe.addTattoo("PARENT:"+mob.Name());
							String race2=mob.baseCharStats().getMyRace().ID();
							MOB otherParentM=null;
							if(z>y)
							{
								race2=text().substring(z+1).trim();
								otherParentM=CMLib.players().getLoadPlayer(text().substring(y+1,z));
								desc+=" and "+text().substring(y+1,z);
								if(otherParentM != null)
								{
									babe.addTattoo("PARENT:"+otherParentM.Name());
								}
							}
							desc+=".";
							mob.curState().setMovement(0);
							mob.curState().setHitPoints(mob.curState().getHitPoints()/2);
							mob.location().show(mob,null,CMMsg.MSG_NOISE,L("***** <S-NAME> !!!GIVE(S) BIRTH!!! ******"));
							if(CMLib.dice().rollPercentage()>5)
							{
								Ability A=mob.fetchEffect(ID());
								while(A!=null)
								{
									mob.delEffect(A);
									A.setAffectedOne(null);
									A=mob.fetchEffect(ID());
								}
								A=mob.fetchAbility(ID());
								while(A!=null)
								{
									mob.delAbility(A);
									A.setAffectedOne(null);
									A=mob.fetchAbility(ID());
								}
							}
							Race R=getRace(babe,race1,race2);
							if(R==null)
								R=mob.baseCharStats().getMyRace();
							String name=CMLib.english().startWithAorAn(R.makeMobName(gender, 2)).toLowerCase();
							babe.setName(name);
							CMLib.factions().setAlignment(babe,Faction.Align.GOOD);
							for(final Pair<Clan,Integer> p : CMLib.clans().findRivalrousClans(mob))
								babe.setClan(p.first.clanID(),p.first.getAutoPosition());
							babe.setLiegeID(mob.getLiegeID());
							babe.setDescription(desc);
							babe.setDisplayText(L("@x1 is here.",name));
							CMLib.beanCounter().clearZeroMoney(babe,null);
							babe.baseCharStats().setMyRace(R);
							babe.baseCharStats().setStat(CharStats.STAT_CHARISMA,10);
							babe.baseCharStats().setStat(CharStats.STAT_CONSTITUTION,6);
							babe.baseCharStats().setStat(CharStats.STAT_DEXTERITY,2);
							babe.baseCharStats().setStat(CharStats.STAT_GENDER,gender);
							babe.baseCharStats().setStat(CharStats.STAT_INTELLIGENCE,2);
							babe.baseCharStats().setStat(CharStats.STAT_STRENGTH,1);
							babe.baseCharStats().setStat(CharStats.STAT_WISDOM,1);
							babe.baseCharStats().getMyRace().startRacing(babe,false);
							babe.basePhyStats().setHeight(babe.basePhyStats().height()/10);
							babe.basePhyStats().setWeight(babe.basePhyStats().weight()/10);
							babe.baseState().setHitPoints(1);
							babe.baseState().setMana(0);
							babe.baseState().setMovement(0);
							babe.recoverCharStats();
							if(!CMLib.flags().isAnimalIntelligence(babe))
							{
								if(CMLib.dice().rollPercentage()>50)
								{
									Ability A=mob.fetchEffect("Allergies");
									if(A!=null)
									{
										A=(Ability)A.copyOf();
										babe.addNonUninvokableEffect(A);
									}
									else
									{
										A=CMClass.getAbility("Allergies");
										if(A!=null)
											A.invoke(babe,babe,true,0);
									}
								}
								final Ability STAT=CMClass.getAbility("Prop_StatTrainer");
								if(STAT!=null)
								{
									STAT.setMiscText("CHA=10 CON=6 DEX=2 INT=2 STR=1 WIS=1");
									babe.addNonUninvokableEffect(STAT);
								}
							}
							final Ability SAFE=CMClass.getAbility("Prop_SafePet");
							if(SAFE!=null)
								babe.addNonUninvokableEffect(SAFE);
							final Ability AGE=CMClass.getAbility("Age");
							if(AGE!=null)
							{
								AGE.setMiscText(""+System.currentTimeMillis());
								babe.addNonUninvokableEffect(AGE);
							}
							babe.recoverCharStats();
							babe.recoverPhyStats();
							babe.recoverMaxState();
							babe.resetToMaxState();
							final Item I=CMClass.getItem("GenCaged");
							((CagedAnimal)I).cageMe(babe);
							((CagedAnimal)I).setCageFlagsBitmap(CagedAnimal.CAGEFLAG_TO_MOB_PROGRAMMATICALLY);
							if(AGE != null)
								I.addNonUninvokableEffect((Ability)AGE.copyOf());
							name=CMLib.english().startWithAorAn(R.makeMobName((char)babe.baseCharStats().getStat(CharStats.STAT_GENDER), 1)).toLowerCase();
							I.setName(name);
							I.setDisplayText(L("@x1 is here.",name));
							I.recoverPhyStats();
							mob.location().addItem(I);
							final Behavior B=CMClass.getBehavior("Emoter");
							B.setParms(Age.happyBabyEmoter);
							I.addBehavior(B);
							I.text();
							if((!mob.isMonster())&&(mob.soulMate()==null))
							{
								if((CMLib.dice().rollPercentage()<20)&&(mob.fetchEffect("Disease_Depression")==null))
								{
									final Ability A=CMClass.getAbility("Disease_Depression");
									if(A!=null)
										A.invoke(mob,mob,true,0);
								}
							}
							if((mob.playerStats()!=null)||((otherParentM!=null)&&(otherParentM.playerStats()!=null)))
							{
								CMLib.coffeeTables().bump(mob,CoffeeTableRow.STAT_BIRTHS);
								final List<String> channels=CMLib.channels().getFlaggedChannelNames(ChannelsLibrary.ChannelFlag.BIRTHS);
								for(int i=0;i<channels.size();i++)
									CMLib.commands().postChannel(mob,channels.get(i),L("@x1 has just given birth to @x2!",mob.name(),I.name()),true);
								String parent=mob.Name();
								if(mob.isMonster()&&(otherParentM!=null))
									parent=otherParentM.Name();
								if(AGE!=null)
									CMLib.database().DBCreateData(parent,"HEAVEN",parent+"/HEAVEN/"+AGE.text(),I.ID()+"/"+I.basePhyStats().ability()+"/"+I.text());
							}
						}
						else
							mob.tell(L("You are in labor!!"));

					}
					else
					{
						// pregnant folk get fatigued more often.
						if(mob.maxState().getFatigue()>Long.MIN_VALUE/2)
							mob.curState().adjFatigue(monthsRemaining*100,mob.maxState());
						if((monthsRemaining<=1)&&(CMLib.dice().rollPercentage()==1))
						{
							if(CMLib.flags().isSleeping(mob))
								mob.enqueCommand(CMParms.parse("WAKE"),MUDCmdProcessor.METAFLAG_FORCED,0);
							mob.tell(L("Oh! You had a contraction!"));
						}
						else
						if((monthsRemaining<=3)&&(CMLib.dice().rollPercentage()==1)&&(CMLib.dice().rollPercentage()==1))
							mob.tell(L("You feel a kick in your gut."));
						else
						if((monthsRemaining>8)&&(mob.location()!=null)&&(mob.location().getArea().getTimeObj().getHourOfDay()<2)&&(CMLib.dice().rollPercentage()==1))
						{
							if(CMLib.dice().rollPercentage()>25)
								mob.tell(L("You feel really sick this morning."));
							else
								mob.location().show(mob,null,CMMsg.MSG_NOISYMOVEMENT,L("**BLEH** <S-NAME> just threw up."));
						}
					}
				}
			}
		}
		return true;
	}

	@Override
	public boolean invoke(MOB mob, List<String> commands, Physical givenTarget, boolean auto, int asLevel)
	{
		final MOB target=getTarget(mob,commands,givenTarget);
		if(target==null)
			return false;
		if(!super.invoke(mob,commands,givenTarget,auto,asLevel))
			return false;
		final boolean success=proficiencyCheck(mob,0,auto);
		long start=System.currentTimeMillis();
		final Race R=target.charStats().getMyRace();
		long tickspermudmonth=CMProps.getIntVar(CMProps.Int.TICKSPERMUDDAY);
		final TimeClock C=CMLib.time().localClock(target.getStartRoom());
		tickspermudmonth=tickspermudmonth*C.getDaysInMonth();
		int birthmonths=(int)Math.round(CMath.mul((R.getAgingChart()[1]-R.getAgingChart()[0])*C.getMonthsInYear(),0.75));
		if(birthmonths<=0)
			birthmonths=5;
		final long ticksperbirthperiod=tickspermudmonth*birthmonths;
		final long millisperbirthperiod=ticksperbirthperiod*CMProps.getTickMillis();

		long end=start+millisperbirthperiod;
		if(success)
		{
			if(!auto)
			{
				end=start;
				start-=millisperbirthperiod;
			}
			if(mob.location().show(mob,target,this,CMMsg.TYP_GENERAL,auto?null:L("<S-NAME> imgregnate(s) <T-NAMESELF>.")))
			{
				setMiscText(start+"/"+end+"/"+mob.Name()+"/"+mob.charStats().getMyRace().ID());
				final List<String> channels=CMLib.channels().getFlaggedChannelNames(ChannelsLibrary.ChannelFlag.CONCEPTIONS);
				for(int i=0;i<channels.size();i++)
					CMLib.commands().postChannel(channels.get(i),mob.clans(),L("@x1 is now in a 'family way'.",target.name()),true);
				target.addNonUninvokableEffect((Ability)copyOf());
			}
		}
		else
		if(!auto)
			return beneficialVisualFizzle(mob,target,L("<S-NAME> attempt(s) to impregnate <T-NAMESELF>, but fail(s)!"));
		return success;
	}
}