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;
}
}