/
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.Traps;
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 2001-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 Trap_Trap extends StdAbility implements Trap
{
	@Override
	public String ID()
	{
		return "Trap_Trap";
	}

	private final static String	localizedName	= CMLib.lang().L("a Trap!");

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

	@Override
	protected int canAffectCode()
	{
		return Ability.CAN_EXITS | Ability.CAN_ROOMS | Ability.CAN_ITEMS;
	}

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

	protected static MOB benefactor=CMClass.getMOB("StdMOB");
	protected boolean sprung=false;
	protected Room myPit=null;
	protected Room myPitUp=null;
	protected int reset=60; // 5 minute reset is standard
	protected int trapType(){return CMLib.dice().roll(1,3,-1);}

	public Trap_Trap()
	{
		super();
		if(benefactor==null)
			benefactor=CMClass.getMOB("StdMOB");
	}

	@Override
	public void activateBomb()
	{
	}

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

	@Override
	public boolean sprung()
	{
		return sprung;
	}

	@Override
	public boolean disabled()
	{
		return sprung;
	}

	@Override
	public void disable()
	{
		sprung = true;
	}

	@Override
	public void setReset(int Reset)
	{
		reset = Reset;
	}

	@Override
	public int getReset()
	{
		return reset;
	}

	// as these are not standard traps, we return this!
	@Override
	public boolean maySetTrap(MOB mob, int asLevel)
	{
		return false;
	}

	@Override
	public boolean canSetTrapOn(MOB mob, Physical P)
	{
		return false;
	}

	@Override
	public boolean canReSetTrap(MOB mob)
	{
		return false;
	}

	@Override
	public List<Item> getTrapComponents()
	{
		return new Vector<Item>(0);
	}

	@Override
	public String requiresToSet()
	{
		return "";
	}

	@Override
	public Trap setTrap(MOB mob, Physical P, int trapBonus, int qualifyingClassLevel, boolean perm)
	{
		if(P==null)
			return null;
		int level=mob.phyStats().level();
		if(level<qualifyingClassLevel)
			level=qualifyingClassLevel;
		level+=trapBonus;
		if(level>=100)
			level=99;
		final int rejuv=((100-level)*30);
		final Trap T=(Trap)copyOf();
		T.setReset(rejuv);
		T.setInvoker(mob);
		P.addEffect(T);
		T.setAbilityCode(trapBonus);
		if(perm)
		{
			T.setSavable(true);
			T.makeNonUninvokable();
		}
		else
		{
			T.setSavable(false);
			CMLib.threads().startTickDown(T,Tickable.TICKID_TRAP_DESTRUCTION,level*30);
		}
		return T;
	}

	public void gas(MOB mob)
	{
		if(CMLib.dice().rollPercentage()<mob.charStats().getSave(CharStats.STAT_SAVE_TRAPS))
			mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> avoid(s) a gas trap set in <T-NAME>."));
		else
		if(mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> trigger(s) a trap set in <T-NAME>!")))
			if(mob.phyStats().level()>15)
			{
				mob.location().showHappens(CMMsg.MSG_OK_ACTION,L("The room fills with gas!"));
				for(int i=0;i<mob.location().numInhabitants();i++)
				{
					final MOB target=mob.location().fetchInhabitant(i);
					if(target==null)
						break;

					int dmg=CMLib.dice().roll(target.phyStats().level(),10,1);
					final CMMsg msg=CMClass.getMsg(invoker(),target,this,CMMsg.MSG_OK_ACTION,CMMsg.MSK_MALICIOUS_MOVE|CMMsg.TYP_GAS,CMMsg.MSG_NOISYMOVEMENT,null);
					if(target.location().okMessage(target,msg))
					{
						target.location().send(target,msg);
						if(msg.value()>0)
							dmg=(int)Math.round(CMath.div(dmg,2.0));
						CMLib.combat().postDamage(invoker(),target,this,dmg,CMMsg.MASK_ALWAYS|CMMsg.MASK_MALICIOUS|CMMsg.TYP_GAS,Weapon.TYPE_GASSING,L("The gas <DAMAGE> <T-NAME>!"));
					}
				}
			}
			else
			{
				final MOB target=mob;
				int dmg=CMLib.dice().roll(target.phyStats().level(),10,1);
				final CMMsg msg=CMClass.getMsg(invoker(),target,this,CMMsg.MSG_OK_ACTION,CMMsg.MSK_MALICIOUS_MOVE|CMMsg.TYP_GAS,CMMsg.MSG_NOISYMOVEMENT,null);
				if(target.location().okMessage(target,msg))
				{
					target.location().send(target,msg);
					if(msg.value()>0)
						dmg=(int)Math.round(CMath.div(dmg,2.0));
					CMLib.combat().postDamage(invoker(),target,this,dmg,CMMsg.MASK_ALWAYS|CMMsg.MASK_MALICIOUS|CMMsg.TYP_GAS,Weapon.TYPE_GASSING,L("A sudden blast of gas <DAMAGE> <T-NAME>!"));
				}
			}
	}

	public void needle(MOB mob)
	{
		if(CMLib.dice().rollPercentage()<mob.charStats().getSave(CharStats.STAT_SAVE_TRAPS))
			mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> avoid(s) a needle trap set in <T-NAME>."));
		else
		if(mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> trigger(s) a needle trap set in <T-NAME>!")))
		{
			final MOB target=mob;
			int dmg=CMLib.dice().roll(target.phyStats().level(),5,1);
			final CMMsg msg=CMClass.getMsg(invoker(),target,this,CMMsg.MSG_OK_ACTION,CMMsg.MSK_MALICIOUS_MOVE|CMMsg.TYP_JUSTICE,CMMsg.MSG_NOISYMOVEMENT,null);
			if(target.location().okMessage(target,msg))
			{
				target.location().send(target,msg);
				if(msg.value()>0)
					dmg=(int)Math.round(CMath.div(dmg,2.0));
				CMLib.combat().postDamage(invoker(),target,this,dmg,CMMsg.MASK_ALWAYS|CMMsg.MASK_MALICIOUS|CMMsg.TYP_JUSTICE,Weapon.TYPE_PIERCING,L("The needle <DAMAGE> <T-NAME>!"));

				final Ability P=CMClass.getAbility("Poison");
				if(P!=null)
					P.invoke(invoker(),target,true,0);
			}
		}
	}

	public void blade(MOB mob)
	{
		if(CMLib.dice().rollPercentage()<mob.charStats().getSave(CharStats.STAT_SAVE_TRAPS))
			mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> avoid(s) a blade trap set in <T-NAME>."));
		else
		if(mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> trigger(s) a blade trap set in <T-NAME>!")))
		{
			final MOB target=mob;
			int dmg=CMLib.dice().roll(target.phyStats().level(),2,0);
			final CMMsg msg=CMClass.getMsg(invoker(),target,this,CMMsg.MSG_OK_ACTION,CMMsg.MSK_MALICIOUS_MOVE|CMMsg.TYP_JUSTICE,CMMsg.MSG_NOISYMOVEMENT,null);
			if(target.location().okMessage(target,msg))
			{
				target.location().send(target,msg);
				if(msg.value()>0)
					dmg=(int)Math.round(CMath.div(dmg,2.0));
				final Ability P=CMClass.getAbility("Poison");
				if(P!=null)
					P.invoke(invoker(),target,true,0);
				CMLib.combat().postDamage(invoker(),target,this,dmg,CMMsg.MASK_ALWAYS|CMMsg.MASK_MALICIOUS|CMMsg.TYP_JUSTICE,Weapon.TYPE_PIERCING,L("The blade <DAMAGE> <T-NAME>!"));
			}
		}
	}

	public void victimOfSpell(MOB mob)
	{
		if(CMLib.dice().rollPercentage()<mob.charStats().getSave(CharStats.STAT_SAVE_TRAPS))
			mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> avoid(s) a magic trap set in <T-NAME>."));
		else
		if(mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> trigger(s) a trap set in <T-NAME>!")))
		{
			String spell=text();
			final int x=spell.indexOf(';');
			Vector<String> V=new Vector<String>();
			V.add(mob.name());
			if(x>0)
			{
				V=CMParms.parse(spell.substring(x+1));
				V.add(0,mob.name());
				spell=spell.substring(0,x);
			}
			final Ability A=CMClass.findAbility(spell);
			if(A==null)
			{
				mob.location().showHappens(CMMsg.MSG_OK_VISUAL,L("But nothing happened..."));
				return;
			}
			A.invoke(invoker(),V,mob,true,0);
		}
	}

	public void fallInPit(MOB mob)
	{
		if(CMLib.flags().isInFlight(mob))
		{
			mob.location().show(mob,null,CMMsg.MSG_OK_ACTION,L("<S-NAME> trigger(s) a trap door beneath <S-HIS-HER> feet! <S-NAME> pause(s) over it in flight."));
			return;
		}
		else
		if(CMLib.dice().rollPercentage()<mob.charStats().getSave(CharStats.STAT_SAVE_TRAPS))
			mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> avoid(s) a trap door beneath <S-HIS-HER> feet."));
		else
		if(mob.location().show(mob,affected,this,CMMsg.MSG_OK_ACTION,L("<S-NAME> trigger(s) a trap door beneath <S-HIS-HER> feet! <S-NAME> fall(s) in!")))
		{
			if((myPit==null)||(myPitUp==null))
			{
				myPitUp=CMClass.getLocale("ClimbableSurface");
				myPitUp.setRoomID("");
				myPitUp.setSavable(false);
				myPitUp.setArea(mob.location().getArea());
				myPitUp.basePhyStats().setDisposition(myPitUp.basePhyStats().disposition()|PhyStats.IS_DARK);
				myPitUp.setDisplayText(L("Inside a dark pit"));
				myPitUp.setDescription(L("The walls here are slick and tall.  The trap door is just above you."));
				myPitUp.recoverPhyStats();

				myPit=CMClass.getLocale("StdRoom");
				myPit.setSavable(false);
				myPit.setRoomID("");
				myPit.setArea(mob.location().getArea());
				myPit.basePhyStats().setDisposition(myPit.basePhyStats().disposition()|PhyStats.IS_DARK);
				myPit.setDisplayText(L("Inside a dark pit"));
				myPit.setDescription(L("The walls here are slick and tall.  You can barely see the trap door well above you."));
				myPit.setRawExit(Directions.UP,CMClass.getExit("StdOpenDoorway"));
				myPit.rawDoors()[Directions.UP]=myPitUp;
				myPitUp.recoverPhyStats();

			}
			final Exit exit=CMClass.getExit("StdClosedDoorway");
			exit.setSavable(false);
			myPitUp.setRawExit(Directions.UP,exit);
			myPitUp.rawDoors()[Directions.UP]=mob.location();
			if((mob.location().getRoomInDir(Directions.DOWN)==null)
			&&(mob.location().getExitInDir(Directions.DOWN)==null))
			{
				mob.location().setRawExit(Directions.DOWN,exit);
				mob.location().rawDoors()[Directions.DOWN]=myPitUp;
			}
			myPit.bringMobHere(mob,false);
			if(mob.phyStats().weight()<5)
				mob.location().show(mob,null,CMMsg.MSG_OK_ACTION,L("<S-NAME> float(s) gently into the pit!"));
			else
			{
				mob.location().show(mob,null,CMMsg.MSG_OK_ACTION,L("<S-NAME> hit(s) the pit floor with a THUMP!"));
				final int damage=CMLib.dice().roll(mob.phyStats().level(),3,1);
				CMLib.combat().postDamage(invoker(),mob,this,damage,CMMsg.MASK_MALICIOUS|CMMsg.TYP_JUSTICE,-1,null);
			}
			CMLib.commands().postLook(mob,true);
		}
	}

	@Override
	public MOB invoker()
	{
		if(invoker==null)
			return benefactor;
		return super.invoker();
	}

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

	@Override
	public void spring(MOB target)
	{
		sprung=true;
		benefactor.setLocation(target.location());
		benefactor.basePhyStats().setLevel(target.phyStats().level());
		benefactor.recoverCharStats();
		benefactor.recoverPhyStats();
		switch(trapType())
		{
		case TRAP_GAS:
			gas(target);
			break;
		case TRAP_NEEDLE:
			needle(target);
			break;
		case TRAP_PIT_BLADE:
			if(affected instanceof Exit)
				fallInPit(target);
			else
				blade(target);
			break;
		case TRAP_SPELL:
			victimOfSpell(target);
			break;
		default:
			target.location().show(target,null,CMMsg.MSG_OK_ACTION,L("<S-NAME> trigger(s) a trap, but it appears to have misfired."));
			break;
		}

		if((getReset()>0)&&(getReset()<Integer.MAX_VALUE))
			CMLib.threads().startTickDown(this,Tickable.TICKID_TRAP_RESET,getReset());
		else
			unInvoke();
	}

	@Override
	public void resetTrap(MOB mob)
	{
		if(sprung())
		{
			sprung=false;
			if(!isABomb())
				CMLib.threads().deleteTick(this, Tickable.TICKID_TRAP_RESET);
		}
	}
	
	@Override
	public void unInvoke()
	{
		if((trapType()==Trap.TRAP_PIT_BLADE)
		&&(affected instanceof Exit)
		&&(myPit!=null)
		&&(canBeUninvoked())
		&&(myPitUp!=null))
		{
			final Room R=myPitUp.getRoomInDir(Directions.UP);
			if((R!=null)&&(R.getRoomInDir(Directions.DOWN)==myPitUp))
			{
				R.rawDoors()[Directions.DOWN]=null;
				R.setRawExit(Directions.DOWN,null);
			}
			/**
			don't do this, cuz someone might still be down there.
			myPitUp.rawDoors()[Directions.UP]=null;
			myPitUp.getRawExit(Directions.UP]=null;
			myPitUp.rawDoors()[Directions.DOWN]=null;
			myPitUp.getRawExit(Directions.DOWN]=null;
			myPit.rawDoors()[Directions.UP]=null;
			myPit.getRawExit(Directions.UP]=null;
			*/
			if(myPit!=null)
				myPit.destroy();
			if(myPitUp!=null)
				myPitUp.destroy();
		}
		super.unInvoke();
	}

	@Override
	public boolean tick(Tickable ticking, int tickID)
	{
		if(!super.tick(ticking,tickID))
			return false;
		if(tickID==Tickable.TICKID_TRAP_RESET)
		{
			sprung=false;
			return false;
		}
		else
		if(tickID==Tickable.TICKID_TRAP_DESTRUCTION)
		{
			unInvoke();
			return false;
		}
		return true;
	}
}