package com.planet_ink.coffee_mud.Abilities.Properties; 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 2002-2019 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 Prop_Familiar extends Property { @Override public String ID() { return "Prop_Familiar"; } @Override public String name() { return "Find Familiar Property"; } protected String displayText = L("Familiarity with an animal"); @Override public String displayText() { return displayText; } @Override protected int canAffectCode() { return Ability.CAN_MOBS; } protected enum Familiar { DOG("dog"), TURTLE("turtle"), CAT("cat"), BAT("bat"), RAT("rat"), SNAKE("snake"), OWL("owl"), RABBIT("rabbit"), RAVEN("raven"), PARROT("parrot"), SPIDERMONKEY("spidermonkey"), BOA_CONSTRICTOR("boa constrictor"), IGUANA("iguana"), SEATURTLE("sea turtle") ; public String name; private Familiar(final String name) { this.name=name; } } protected MOB familiarTo = null; protected MOB familiarWith = null; protected boolean imthedaddy = false; protected Familiar familiarType = Familiar.DOG; protected int[] lastBreathablesSet = null; protected int[] newBreathablesSet = null; protected Map<String, Language> myLanguages = new Hashtable<String, Language>(); @Override public String accountForYourself() { return "is a familiar MOB"; } @Override public long flags() { return Ability.FLAG_ADJUSTER; } public boolean removeMeFromFamiliarTo() { if(familiarTo!=null) { final Ability A=familiarTo.fetchEffect(ID()); if(A!=null) { familiarTo.delEffect(A); /*if(!familiarTo.amDead()) { CMLib.leveler().postExperience(familiarTo,null,null,-50,false); familiarTo.tell(L("You`ve just lost 50 experience points for losing your familiar")); }*/ familiarTo.recoverCharStats(); familiarTo.recoverPhyStats(); } } if(familiarWith!=null) { final Ability A=familiarWith.fetchEffect(ID()); if(A!=null) { familiarWith.delEffect(A); familiarWith.recoverCharStats(); familiarWith.recoverPhyStats(); } if(familiarWith.amDead()) familiarWith.setLocation(null); familiarWith.destroy(); familiarWith.setLocation(null); } return false; } @Override public boolean tick(final Tickable ticking, final int tickID) { if(tickID==Tickable.TICKID_MOB) { if(!(affected instanceof MOB)) return removeMeFromFamiliarTo(); if(((familiarTo != null) && (familiarTo.amDestroyed())) ||((familiarWith != null) && (familiarWith.amDestroyed()))) { familiarTo=null; familiarWith=null; imthedaddy=false; } final MOB familiar=(MOB)affected; if(familiar.amDead()) return removeMeFromFamiliarTo(); if((!imthedaddy) &&(familiarTo==null) &&(familiarWith==null) &&(CMLib.flags().isInTheGame((MOB)affected,true)) &&(((MOB)affected).amFollowing()!=null) &&(CMLib.flags().isInTheGame(((MOB)affected).amFollowing(),true))) { final MOB following=((MOB)affected).amFollowing(); familiarWith=(MOB)affected; familiarTo=following; final Prop_Familiar F=(Prop_Familiar)copyOf(); F.setSavable(false); F.imthedaddy=true; F.familiarWith=(MOB)affected; F.familiarTo = following; // yes, points to self following.delEffect(following.fetchEffect(F.ID())); following.addEffect(F); following.recoverCharStats(); following.recoverPhyStats(); } if((familiarWith!=null) &&(familiarTo!=null) &&((familiarWith.amFollowing()==null) ||(familiarWith.amFollowing()!=familiarTo)) &&(CMLib.flags().isInTheGame(familiarWith,true))) removeMeFromFamiliarTo(); } return super.tick(ticking,tickID); } @Override public void affectPhyStats(final Physical affected, final PhyStats affectableStats) { final MOB familiarWith=this.familiarWith; final MOB familiarTo=this.familiarTo; if((familiarWith!=null) &&(familiarTo!=null) &&(familiarWith.location()==familiarTo.location())) { switch(familiarType) { case DOG: affectableStats.setSensesMask(affectableStats.sensesMask()|PhyStats.CAN_SEE_HIDDEN); break; case TURTLE: break; case CAT: break; case BAT: if(((affectableStats.sensesMask()&PhyStats.CAN_NOT_SEE)>0)&&(affected instanceof MOB)) affectableStats.setSensesMask(affectableStats.sensesMask()-PhyStats.CAN_NOT_SEE); break; case RAT: break; case SNAKE: break; case OWL: affectableStats.setSensesMask(affectableStats.sensesMask()|PhyStats.CAN_SEE_INFRARED); break; case RABBIT: break; case RAVEN: break; case BOA_CONSTRICTOR: break; case IGUANA: break; case PARROT: if((affected == familiarWith)&&(!familiarWith.isInCombat())) { affectableStats.addAmbiance(L("on @x1`s shoulder",familiarTo.name())); affectableStats.setDisposition(CMath.unsetb(affectableStats.disposition(), PhyStats.IS_FLYING)); } break; case SEATURTLE: break; case SPIDERMONKEY: break; } } } protected Language getMyAnimalSpeak(final MOB M, final String ID) { if((M!=null) &&(ID!=null) &&(ID.length()>0)) { synchronized(myLanguages) { Language lA=myLanguages.get(ID); if(lA!=null) return lA; lA=(Language)CMClass.getAbility(ID); lA.setProficiency(100); lA.setAffectedOne(M); lA.setBeingSpoken(lA.ID(), true); myLanguages.put(ID, lA); return lA; } } return null; } protected Language getAnimalSpeak(final MOB M) { if((M!=null) &&(M==familiarWith)) { final Race r=M.charStats().getMyRace(); for(Ability A : r.racialAbilities(M)) { if(((A.classificationCode()&Ability.ALL_ACODES)==Ability.ACODE_LANGUAGE) &&(A instanceof Language)) { final Ability effectA=M.fetchEffect(A.ID()); if(effectA==null) { A.autoInvocation(M, false); A=M.fetchEffect(A.ID()); } if((effectA!=null)&&(((Language)effectA).beingSpoken(effectA.ID()))) return (Language)effectA; } } } return null; } @Override public boolean okMessage(final Environmental myHost, final CMMsg msg) { if(((msg.targetMajor()&CMMsg.MASK_MALICIOUS)>0) &&(!CMath.bset(msg.sourceMajor(),CMMsg.MASK_ALWAYS)) &&(familiarWith!=null) &&(familiarType==Familiar.RABBIT) &&((msg.amITarget(familiarWith))||(msg.amITarget(familiarTo))) &&(familiarWith.location()==familiarTo.location()) ) { final MOB target=(MOB)msg.target(); if((!target.isInCombat()) &&(msg.source().location()==target.location()) &&(msg.source().getVictim()!=target)) { msg.source().tell(L("You are too much in awe of @x1",target.name(msg.source()))); if(familiarWith.getVictim()==msg.source()) familiarWith.makePeace(true); if(familiarTo.getVictim()==msg.source()) familiarTo.makePeace(true); return false; } } if(((msg.sourceMinor()==CMMsg.TYP_SPEAK) ||(msg.sourceMinor()==CMMsg.TYP_ORDER) ||(msg.sourceMinor()==CMMsg.TYP_TELL)) &&(msg.sourceMessage()!=null) &&(msg.target()==familiarWith) &&(familiarWith!=null) &&(familiarTo!=null) &&(familiarWith.location()==familiarTo.location())) { if(msg.amISource(familiarTo) &&(msg.target() instanceof MOB) &&((msg.tool()==null) || (!(msg.tool() instanceof Language)) ||(familiarWith.charStats().getMyRace().racialAbilities(familiarWith).find(msg.tool().ID())==null))) { Language lA=this.getAnimalSpeak(familiarWith); if(lA!=null) lA=getMyAnimalSpeak(familiarTo,lA.ID()); if(lA!=null) lA.okMessage(familiarTo, msg); } } return super.okMessage(myHost,msg); } @Override public void executeMsg(final Environmental host, final CMMsg msg) { if((msg.sourceMinor()==CMMsg.TYP_DEATH) &&((msg.source()==familiarWith)||(msg.source()==familiarTo))) removeMeFromFamiliarTo(); if(((msg.sourceMinor()==CMMsg.TYP_SPEAK) ||(msg.sourceMinor()==CMMsg.TYP_TELL) ||(msg.sourceMinor()==CMMsg.TYP_ORDER)) &&(msg.sourceMessage()!=null) &&(familiarWith!=null) &&(familiarTo!=null) &&(familiarWith.location()==familiarTo.location())) { if((msg.amISource(familiarWith)) &&(msg.tool() instanceof Ability) &&((((Ability)msg.tool()).classificationCode()&Ability.ALL_ACODES)==Ability.ACODE_LANGUAGE) &&(familiarTo.fetchEffect(msg.tool().ID())==null) &&(msg.source().charStats().getMyRace().racialAbilities(msg.source()).find(msg.tool().ID())!=null)) { final String str=CMStrings.getSayFromMessage(msg.sourceMessage()); if(str!=null) { if(CMath.bset(msg.sourceMajor(),CMMsg.MASK_CHANNEL)) msg.addTrailerMsg(CMClass.getMsg(msg.source(),null,null,CMMsg.NO_EFFECT,CMMsg.NO_EFFECT,msg.othersCode(),L("@x1 (translated from @x2)",CMStrings.substituteSayInMessage(msg.othersMessage(),str),msg.tool().name()))); else if(msg.amITarget(affected)&&(msg.targetMessage()!=null)) msg.addTrailerMsg(CMClass.getMsg(msg.source(),affected,null,CMMsg.NO_EFFECT,msg.targetCode(),CMMsg.NO_EFFECT,L("@x1 (translated from @x2)",CMStrings.substituteSayInMessage(msg.targetMessage(),str),msg.tool().name()))); else if((msg.othersMessage()!=null)&&(msg.othersMessage().indexOf('\'')>0)) { String otherMes=msg.othersMessage(); if(msg.target()!=null) otherMes=CMLib.coffeeFilter().fullOutFilter(familiarTo.session(),familiarTo,msg.source(),msg.target(),msg.tool(),otherMes,false); msg.addTrailerMsg(CMClass.getMsg(msg.source(),affected,null,CMMsg.NO_EFFECT,msg.othersCode(),CMMsg.NO_EFFECT,L("@x1 (translated from @x2)",CMStrings.substituteSayInMessage(otherMes,str),msg.tool().name()))); } } } else if(msg.amISource(familiarTo) &&(msg.target() == familiarWith) &&((msg.tool()==null) || (!(msg.tool() instanceof Language)) ||(((MOB)msg.target()).charStats().getMyRace().racialAbilities((MOB)msg.target()).find(msg.tool().ID())==null))) { Language lA=this.getAnimalSpeak(familiarWith); if(lA!=null) lA=getMyAnimalSpeak(familiarTo,lA.ID()); if(lA!=null) lA.executeMsg(familiarTo, msg); } } super.executeMsg(host,msg); } @Override public void setMiscText(String newText) { super.setMiscText(newText); if(CMath.isInteger(newText)) familiarType=Familiar.values()[CMath.s_int(newText)]; else { if(newText.trim().length()>2) { newText=newText.trim(); for(int i=0;i<Familiar.values().length;i++) { if(Familiar.values()[i].name().equalsIgnoreCase(newText)) { familiarType=Familiar.values()[i]; break; } if(Familiar.values()[i].name.equalsIgnoreCase(newText)) { familiarType=Familiar.values()[i]; break; } } } } displayText=L("(Familiarity with the @x1)",familiarType.name); } @Override public void affectCharStats(final MOB affectedMOB, final CharStats affectableStats) { if((familiarWith!=null) &&(familiarTo!=null) &&(familiarWith.location()==familiarTo.location())) switch(familiarType) { case DOG: affectableStats.setStat(CharStats.STAT_STRENGTH,affectableStats.getStat(CharStats.STAT_STRENGTH)+1); break; case TURTLE: { final int[] breatheables=affectableStats.getBreathables(); if(breatheables.length==0) return; if((lastBreathablesSet!=breatheables)||(newBreathablesSet==null)) { newBreathablesSet=Arrays.copyOf(affectableStats.getBreathables(),affectableStats.getBreathables().length+2); newBreathablesSet[newBreathablesSet.length-1]=RawMaterial.RESOURCE_SALTWATER; newBreathablesSet[newBreathablesSet.length-2]=RawMaterial.RESOURCE_FRESHWATER; Arrays.sort(newBreathablesSet); lastBreathablesSet=breatheables; } affectableStats.setBreathables(newBreathablesSet); affectableStats.setStat(CharStats.STAT_STRENGTH,affectableStats.getStat(CharStats.STAT_STRENGTH)+1); break; } case CAT: affectableStats.setStat(CharStats.STAT_DEXTERITY,affectableStats.getStat(CharStats.STAT_DEXTERITY)+1); if(affectableStats.getStat(CharStats.STAT_SAVE_PARALYSIS)<500) affectableStats.setStat(CharStats.STAT_SAVE_PARALYSIS,affectableStats.getStat(CharStats.STAT_SAVE_PARALYSIS)+100); break; case BAT: affectableStats.setStat(CharStats.STAT_DEXTERITY,affectableStats.getStat(CharStats.STAT_DEXTERITY)+1); break; case RAT: if(affectableStats.getStat(CharStats.STAT_SAVE_DISEASE)<500) affectableStats.setStat(CharStats.STAT_SAVE_DISEASE,affectableStats.getStat(CharStats.STAT_SAVE_DISEASE)+100); affectableStats.setStat(CharStats.STAT_CONSTITUTION,affectableStats.getStat(CharStats.STAT_CONSTITUTION)+1); break; case SNAKE: if(affectableStats.getStat(CharStats.STAT_SAVE_POISON)<500) affectableStats.setStat(CharStats.STAT_SAVE_POISON,affectableStats.getStat(CharStats.STAT_SAVE_POISON)+100); affectableStats.setStat(CharStats.STAT_CONSTITUTION,affectableStats.getStat(CharStats.STAT_CONSTITUTION)+1); break; case OWL: affectableStats.setStat(CharStats.STAT_WISDOM,affectableStats.getStat(CharStats.STAT_WISDOM)+1); break; case RABBIT: affectableStats.setStat(CharStats.STAT_CHARISMA,affectableStats.getStat(CharStats.STAT_CHARISMA)+1); break; case RAVEN: if(affectableStats.getStat(CharStats.STAT_SAVE_UNDEAD)<500) affectableStats.setStat(CharStats.STAT_SAVE_UNDEAD,affectableStats.getStat(CharStats.STAT_SAVE_UNDEAD)+100); affectableStats.setStat(CharStats.STAT_INTELLIGENCE,affectableStats.getStat(CharStats.STAT_INTELLIGENCE)+1); break; case BOA_CONSTRICTOR: affectableStats.setStat(CharStats.STAT_STRENGTH,affectableStats.getStat(CharStats.STAT_STRENGTH)+1); break; case IGUANA: if(affectableStats.getStat(CharStats.STAT_SAVE_UNDEAD)<500) affectableStats.setStat(CharStats.STAT_SAVE_UNDEAD,affectableStats.getStat(CharStats.STAT_SAVE_UNDEAD)+100); affectableStats.setStat(CharStats.STAT_INTELLIGENCE,affectableStats.getStat(CharStats.STAT_INTELLIGENCE)+1); break; case PARROT: affectableStats.setStat(CharStats.STAT_CHARISMA,affectableStats.getStat(CharStats.STAT_CHARISMA)+1); break; case SEATURTLE: final int[] breatheables=affectableStats.getBreathables(); if(breatheables.length==0) return; if((lastBreathablesSet!=breatheables)||(newBreathablesSet==null)) { newBreathablesSet=Arrays.copyOf(affectableStats.getBreathables(),affectableStats.getBreathables().length+2); newBreathablesSet[newBreathablesSet.length-1]=RawMaterial.RESOURCE_SALTWATER; newBreathablesSet[newBreathablesSet.length-2]=RawMaterial.RESOURCE_FRESHWATER; Arrays.sort(newBreathablesSet); lastBreathablesSet=breatheables; } affectableStats.setBreathables(newBreathablesSet); affectableStats.setStat(CharStats.STAT_CONSTITUTION,affectableStats.getStat(CharStats.STAT_CONSTITUTION)+1); break; case SPIDERMONKEY: affectableStats.setStat(CharStats.STAT_DEXTERITY,affectableStats.getStat(CharStats.STAT_DEXTERITY)+1); if(affectableStats.getStat(CharStats.STAT_SAVE_PARALYSIS)<500) affectableStats.setStat(CharStats.STAT_SAVE_PARALYSIS,affectableStats.getStat(CharStats.STAT_SAVE_PARALYSIS)+100); break; default: break; } } }