package com.planet_ink.coffee_mud.Libraries;
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.Libraries.interfaces.*;
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.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;
import java.util.*;
/*
Copyright 2006-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 TimsLibrary extends StdLibrary implements ItemBalanceLibrary
{
@Override
public String ID()
{
return "TimsLibrary";
}
@Override
public int timsLevelCalculator(final Item I)
{
final List<Ability> props=getTimsAdjResCast(I);
return timsLevelCalculator(I,props);
}
protected double timsDmgModifier(final int weaponClass)
{
double dmgModifier=1.0;
switch(weaponClass)
{
case Weapon.CLASS_FLAILED:
dmgModifier=1.1;
break;
case Weapon.CLASS_EDGED:
dmgModifier=0.8;
break;
case Weapon.CLASS_DAGGER:
dmgModifier=0.5;
break;
case Weapon.CLASS_BLUNT:
case Weapon.CLASS_STAFF:
dmgModifier=0.9;
break;
case Weapon.CLASS_THROWN:
dmgModifier=1.5;
}
return dmgModifier;
}
protected double timsBaseAttackModifier(final int weaponClass)
{
double baseattack=0.0;
switch(weaponClass)
{
case Weapon.CLASS_FLAILED:
baseattack=-5;
break;
case Weapon.CLASS_EDGED:
case Weapon.CLASS_DAGGER:
{
baseattack = 10;
break;
}
}
return baseattack;
}
protected double timsAttackModifier(final int weaponClass)
{
double attModifier=0.0;
switch(weaponClass)
{
case Weapon.CLASS_FLAILED:
attModifier=-0.3;
break;
case Weapon.CLASS_EDGED:
attModifier=0.6;
break;
case Weapon.CLASS_DAGGER:
attModifier=1.3;
break;
case Weapon.CLASS_BLUNT:
case Weapon.CLASS_STAFF:
attModifier=0.3;
}
return attModifier;
}
@Override
public int timsLevelCalculator(final Item itemI, final List<Ability> props)
{
int level=0;
final Item savedI=itemI;
savedI.recoverPhyStats();
//IworkI=(Item)IworkI.copyOf();
//IworkI.recoverPhyStats();
// the item is only ever read, so why copy it?
int otherDam=0;
int otherAtt=0;
int otherArm=0;
for(final Ability A : props)
{
otherArm=-CMath.s_int(A.getStat("STAT-ARMOR"));
otherAtt=CMath.s_int(A.getStat("STAT-ATTACK"));
otherDam=CMath.s_int(A.getStat("STAT-DAMAGE"));
}
final int curArmor=savedI.basePhyStats().armor()+otherArm;
final double curAttack=savedI.basePhyStats().attackAdjustment()+otherAtt;
final double curDamage=savedI.basePhyStats().damage()+otherDam;
final Wearable.CODES codes = Wearable.CODES.instance();
if(itemI instanceof Weapon)
{
double weight=8;
if(weight<1.0)
weight=1.0;
final double range=((Weapon)savedI).getRanges()[1];
final int wclass=((Weapon)savedI).weaponClassification();
final double dmgMod = this.timsDmgModifier(wclass);
final double dmgLevel = Math.floor(((2.0*curDamage/(2.0*(itemI.rawLogicalAnd()?2.0:1.0)+1.0)+(curAttack-weight)/5.0+range)*(range/weight+2.0)/dmgMod))+1;
final double baseAttack = (curAttack - timsBaseAttackModifier(wclass));
double attackLevel;
if(baseAttack < 0)
attackLevel = dmgLevel - baseAttack;
else
if(this.timsAttackModifier(wclass)>0.0)
attackLevel = baseAttack / this.timsAttackModifier(wclass);
else
attackLevel = dmgLevel + baseAttack;
level = (int)Math.round((dmgLevel + attackLevel) / 2.0);
}
else
{
final long worndata=savedI.rawProperLocationBitmap();
double weightpts=0;
for(int i=0;i<codes.location_strength_points().length-1;i++)
{
if(CMath.isSet(worndata,i))
{
weightpts+=codes.location_strength_points()[i+1];
if(!itemI.rawLogicalAnd())
break;
}
}
final int[] leatherPoints = { 0, 0, 1, 5, 10, 16, 23, 31, 40, 49, 58, 67, 76, 85, 94 };
final int[] clothPoints = { 0, 3, 7, 12, 18, 25, 33, 42, 52, 62, 72, 82, 92, 102 };
final int[] metalPoints = { 0, 0, 0, 0, 1, 3, 5, 8, 12, 17, 23, 30, 38, 46, 54, 62, 70, 78, 86, 94 };
final int materialCode=savedI.material()&RawMaterial.MATERIAL_MASK;
int[] useArray=null;
switch(materialCode)
{
case RawMaterial.MATERIAL_METAL:
case RawMaterial.MATERIAL_MITHRIL:
case RawMaterial.MATERIAL_PRECIOUS:
case RawMaterial.MATERIAL_ENERGY:
useArray=metalPoints;
break;
case RawMaterial.MATERIAL_SYNTHETIC:
case RawMaterial.MATERIAL_LEATHER:
case RawMaterial.MATERIAL_GLASS:
case RawMaterial.MATERIAL_ROCK:
case RawMaterial.MATERIAL_WOODEN:
useArray=leatherPoints;
break;
case RawMaterial.MATERIAL_GAS:
default:
useArray=clothPoints;
break;
}
int which=(int)Math.round(CMath.div(curArmor,weightpts)+1);
if(which<0)
which=0;
if(which>=useArray.length)
which=useArray.length-1;
level=useArray[which];
}
level+=itemI.basePhyStats().ability()*5;
for(final Ability A : props)
level += CMath.s_int(A.getStat("STAT-LEVEL"));
//savedI.destroy();
//IworkI.destroy(); // this was a copy
return level;
}
@Override
public boolean fixRejuvItem(final Item I)
{
Ability A=I.fetchEffect("ItemRejuv");
if(A!=null)
{
A=I.fetchEffect("ItemRejuv");
if(A.isSavable())
return false;
A.setSavable(false);
return true;
}
return false;
}
@Override
public List<Ability> getTimsAdjResCast(final Item I)
{
final List<Ability> props=new Vector<Ability>();
Ability A;
for(int i=0;i<I.numEffects();i++)
{
A=I.fetchEffect( i );
if(A instanceof TriggeredAffect)
{
final long flags=A.flags();
final int triggers=((TriggeredAffect) A).triggerMask();
if( CMath.bset( flags, Ability.FLAG_ADJUSTER )
&& (( triggers&(TriggeredAffect.TRIGGER_WEAR_WIELD|TriggeredAffect.TRIGGER_GET|TriggeredAffect.TRIGGER_MOUNT ))>0))
props.add(A);
else
if( CMath.bset( flags, Ability.FLAG_RESISTER )
&& (( triggers&(TriggeredAffect.TRIGGER_WEAR_WIELD|TriggeredAffect.TRIGGER_GET|TriggeredAffect.TRIGGER_MOUNT ))>0))
props.add(A);
else
if( CMath.bset( flags, Ability.FLAG_ZAPPER )
&& (( triggers&(TriggeredAffect.TRIGGER_WEAR_WIELD|TriggeredAffect.TRIGGER_GET|TriggeredAffect.TRIGGER_MOUNT ))>0))
props.add(A);
else
if( CMath.bset( flags, Ability.FLAG_ENABLER )
&& (( triggers&(TriggeredAffect.TRIGGER_WEAR_WIELD|TriggeredAffect.TRIGGER_GET|TriggeredAffect.TRIGGER_MOUNT ))>0))
props.add(A);
else
if( CMath.bset( flags, Ability.FLAG_CASTER )
&& (triggers > 0))
props.add(A);
}
}
return props;
}
private void reportChangesDestroyOldI(final Item oldI, final Item newI, final StringBuffer changes,final int OTLVL, final int TLVL)
{
if((changes == null)||(oldI==null))
return;
final List<Ability> props=getTimsAdjResCast(newI);
final Map<Object,Integer> levels=getItemLevels(newI,props);
final int TLVL2=totalLevels(levels);
changes.append(newI.name()+":"+newI.basePhyStats().level()+"("+OTLVL+")=>"+TLVL2+"("+TLVL+"), ");
for(int i=0;i<oldI.getStatCodes().length;i++)
{
if((!oldI.getStat(oldI.getStatCodes()[i]).equals(newI.getStat(newI.getStatCodes()[i]))))
changes.append(oldI.getStatCodes()[i]+"("+oldI.getStat(newI.getStatCodes()[i])+"->"+newI.getStat(newI.getStatCodes()[i])+"), ");
}
changes.append("\n\r");
oldI.destroy(); // this was a copy
}
@Override
@SuppressWarnings("unchecked")
public boolean itemFix(final Item I, final int lvlOr0, final StringBuffer changes)
{
final Item oldI = (changes!=null)?(Item)I.copyOf():null;
if((I instanceof SpellHolder)
||((I instanceof Wand)&&(lvlOr0<=0)))
{
Vector<Ability> spells=new Vector<Ability>();
if(I instanceof SpellHolder)
spells.addAll(((SpellHolder)I).getSpells());
else
if((I instanceof Wand)&&(((Wand)I).getSpell()!=null))
spells.add(((Wand)I).getSpell());
if(spells.size()==0)
return false;
int levels=0;
spells=(Vector<Ability>)spells.clone();
for (final Ability ability : spells)
levels+=CMLib.ableMapper().lowestQualifyingLevel(ability.ID());
final int level=(int)Math.round(CMath.div(levels, spells.size()));
if(level==I.basePhyStats().level())
return false;
I.basePhyStats().setLevel(level);
I.phyStats().setLevel(level);
if(CMLib.flags().isCataloged(I))
CMLib.catalog().updateCatalog(I);
reportChangesDestroyOldI(oldI,I,changes,level,level);
return true;
}
else
if((I instanceof Weapon)||(I instanceof Armor))
{
int lvl=lvlOr0;
if(lvl <=0)
lvl=I.basePhyStats().level();
I.basePhyStats().setLevel(lvl);
I.phyStats().setLevel(lvl);
final List<Ability> props=getTimsAdjResCast(I);
Map<Object,Integer> levelsMap=getItemLevels(I,props);
int TLVL=totalLevels(levelsMap);
final int OTLVL=TLVL;
if(lvl<0)
{
if(TLVL<=0)
lvl=1;
else
lvl=TLVL;
I.basePhyStats().setLevel(lvl);
I.recoverPhyStats();
fixRejuvItem(I);
if(CMLib.flags().isCataloged(I))
CMLib.catalog().updateCatalog(I);
reportChangesDestroyOldI(oldI,I,changes,OTLVL,TLVL);
return true;
}
if((TLVL>0)&&(TLVL>Math.round(CMath.mul(lvl,1.1))))
{
//int FTLVL=TLVL;
final Set<Object> illegalThings=new HashSet<Object>();
//Log.sysOut("Reset",I.name()+"("+I.basePhyStats().level()+") "+TLVL+", "+I.basePhyStats().armor()+"/"+I.basePhyStats().attackAdjustment()+"/"+I.basePhyStats().damage()+"/"+((adjA!=null)?adjA.text():"null"));
while((TLVL>Math.round(CMath.mul(lvl,1.1)))
&&(illegalThings.size()<levelsMap.size()))
{
Object highestObject=null;
for(final Object o : levelsMap.keySet())
{
if((highestObject==null)
||(levelsMap.get(o).intValue() > levelsMap.get(highestObject).intValue()))
{
if(!illegalThings.contains(o))
highestObject=o;
}
}
if(highestObject==null)
break;
if(highestObject instanceof Weapon)
{
final Ability adjA=getBaseAdjusterAbility(props);
final String s=(adjA!=null)?adjA.text():"";
final int oldAtt=I.basePhyStats().attackAdjustment();
final int oldDam=I.basePhyStats().damage();
toneDownWeapon((Weapon)I,adjA);
if((I.basePhyStats().attackAdjustment()==oldAtt)
&&(I.basePhyStats().damage()==oldDam)
&&((adjA==null)||(adjA.text().equals(s))))
illegalThings.add(highestObject);
}
else
if(highestObject instanceof Item)
{
final Ability adjA=getBaseAdjusterAbility(props);
final String s=(adjA!=null)?adjA.text():"";
final int oldArm=I.basePhyStats().armor();
toneDownArmor((Armor)I,adjA);
if((I.basePhyStats().armor()==oldArm)
&&((adjA==null)||(adjA.text().equals(s))))
illegalThings.add(highestObject);
}
else
if((highestObject instanceof String)
&&(((String)highestObject).equalsIgnoreCase("ABILITY")))
{
if(I.basePhyStats().ability()>0)
I.basePhyStats().setAbility(I.basePhyStats().ability()-1);
else
illegalThings.add("ABILITY");
}
else
if(highestObject instanceof Ability)
{
final Ability A=(Ability)highestObject;
final int prevLevel=CMath.s_int(A.getStat("STAT-LEVEL"));
A.setStat("TONEDOWN-MISC", "90%");
if(CMath.s_int(A.getStat("STAT-LEVEL"))==prevLevel)
{
A.setStat("TONEDOWN-MISC", "90%");
if(CMath.s_int(A.getStat("STAT-LEVEL"))==prevLevel)
{
A.setStat("TONEDOWN-MISC", "50%");
if(CMath.s_int(A.getStat("STAT-LEVEL"))==prevLevel)
illegalThings.add(highestObject);
}
}
}
else
{
Log.errOut(ID(),"What is "+highestObject+"??");
illegalThings.add(highestObject);
}
levelsMap=getItemLevels(I,props);
TLVL=totalLevels(levelsMap);
}
//Log.sysOut("Reset",I.name()+"("+I.basePhyStats().level()+") "+FTLVL+"->"+TLVL+", "+I.basePhyStats().armor()+"/"+I.basePhyStats().attackAdjustment()+"/"+I.basePhyStats().damage()+"/"+((adjA!=null)?adjA.text():"null"));
fixRejuvItem(I);
if(CMLib.flags().isCataloged(I))
CMLib.catalog().updateCatalog(I);
reportChangesDestroyOldI(oldI,I,changes,OTLVL,TLVL);
return true;
}
}
if(fixRejuvItem(I))
{
if(CMLib.flags().isCataloged(I))
CMLib.catalog().updateCatalog(I);
if(oldI!=null)
oldI.destroy();
return true;
}
if(oldI!=null)
oldI.destroy();
return false;
}
@Override
public boolean toneDownValue(final Item I)
{
int hands=0;
int weaponClass=0;
if(I instanceof Coins)
return false;
if(I instanceof Weapon)
{
hands=I.rawLogicalAnd()?2:1;
weaponClass=((Weapon)I).weaponClassification();
}
else
if(!(I instanceof Armor))
return false;
final Map<String,String> H=timsItemAdjustments(I,I.phyStats().level(),I.material(),hands,weaponClass,I.maxRange(),I.rawProperLocationBitmap());
final int newValue=CMath.s_int(H.get("VALUE"));
if((I.baseGoldValue()>newValue)&&(newValue>0))
{
I.setBaseValue(newValue);
return true;
}
return false;
}
@Override
public void balanceItemByLevel(final Item I)
{
int hands=0;
int weaponClass=0;
final int maxRange;
if(I instanceof Weapon)
{
hands=I.rawLogicalAnd()?2:1;
weaponClass=((Weapon)I).weaponClassification();
maxRange=((Weapon)I).getRanges()[1];
}
else
maxRange=I.maxRange();
final Map<String,String> H=timsItemAdjustments(I,I.basePhyStats().level(),I.material(),hands,weaponClass,maxRange,I.rawProperLocationBitmap());
if(I instanceof Weapon)
{
I.basePhyStats().setDamage(CMath.s_int(H.get("DAMAGE")));
I.basePhyStats().setAttackAdjustment(CMath.s_int(H.get("ATTACK")));
I.setBaseValue(CMath.s_int(H.get("VALUE")));
I.recoverPhyStats();
}
else
if(I instanceof Armor)
{
I.basePhyStats().setArmor(CMath.s_int(H.get("ARMOR")));
I.setBaseValue(CMath.s_int(H.get("VALUE")));
I.basePhyStats().setWeight(CMath.s_int(H.get("WEIGHT")));
I.recoverPhyStats();
}
}
@Override
public Map<String, String> timsItemAdjustments(final Item I,
int level,
final int material,
final int hands,
final int wclass,
int reach,
final long worndata)
{
final Hashtable<String,String> vals=new Hashtable<String,String>(); // return obj
final int materialvalue=RawMaterial.CODES.VALUE(material);
final List<Ability> props=getTimsAdjResCast(I);
level-=levelsFromAbility(I);
for(final Ability A : props)
level-=CMath.s_int(A.getStat("STAT-LEVEL"));
if(I instanceof Weapon)
{
int baseattack=(int)Math.round(this.timsBaseAttackModifier(wclass));
int basereach=0;
int maxreach=0;
int thrown = 0;
int basematerial=RawMaterial.MATERIAL_WOODEN;
switch(wclass)
{
case Weapon.CLASS_POLEARM:
{
basereach = 1;
basematerial = RawMaterial.MATERIAL_METAL;
break;
}
case Weapon.CLASS_RANGED:
{
basereach = 1;
maxreach = 5;
break;
}
case Weapon.CLASS_THROWN:
{
basereach = 1;
maxreach = 5;
thrown = 1;
break;
}
case Weapon.CLASS_EDGED:
{
basematerial = RawMaterial.MATERIAL_METAL;
break;
}
case Weapon.CLASS_DAGGER:
{
basematerial = RawMaterial.MATERIAL_METAL;
break;
}
case Weapon.CLASS_SWORD:
{
basematerial = RawMaterial.MATERIAL_METAL;
break;
}
}
final double dmgModifier = this.timsDmgModifier(wclass);
int weight = I.basePhyStats().weight();
if(weight<1)
weight=8;
if(weight>40)
weight=40;
if(basereach>maxreach)
maxreach=basereach;
if(reach<basereach)
{
reach=basereach;
vals.put("MINRANGE",""+basereach);
vals.put("MAXRANGE",""+maxreach);
}
else
if(reach>basereach)
basereach=reach;
int damage=(int)Math.round((((level-1.0)/(((double)reach/(double)weight)+2.0) + ((double)weight-(double)baseattack)/5.0 -reach)*(((hands*2.0)+1.0)/2.0))*dmgModifier);
final int cost=(int)Math.round(2.0*(((double)weight*(double)materialvalue)+((2.0*damage)+baseattack+(reach*10.0))*damage)/((hands+1.0)*(thrown+1.0)));
baseattack += (int)Math.round(level * this.timsAttackModifier(wclass));
if(basematerial==RawMaterial.MATERIAL_METAL)
{
switch(material&RawMaterial.MATERIAL_MASK)
{
case RawMaterial.MATERIAL_MITHRIL:
case RawMaterial.MATERIAL_METAL:
case RawMaterial.MATERIAL_ENERGY:
break;
case RawMaterial.MATERIAL_WOODEN:
case RawMaterial.MATERIAL_SYNTHETIC:
damage-=4;
baseattack-=0;
break;
case RawMaterial.MATERIAL_PRECIOUS:
damage-=4;
baseattack-=10;
break;
case RawMaterial.MATERIAL_LEATHER:
damage-=6;
baseattack-=10;
break;
case RawMaterial.MATERIAL_ROCK:
damage-=2;
baseattack-=10;
break;
case RawMaterial.MATERIAL_GLASS:
damage-=4;
baseattack-=20;
break;
case RawMaterial.MATERIAL_GAS:
default:
damage-=8;
baseattack-=30;
break;
}
switch(material)
{
case RawMaterial.RESOURCE_BALSA:
case RawMaterial.RESOURCE_LIMESTONE:
case RawMaterial.RESOURCE_FLINT:
baseattack-=10;
damage-=2;
break;
case RawMaterial.RESOURCE_CLAY:
baseattack-=20;
damage-=4;
break;
case RawMaterial.RESOURCE_BONE:
baseattack+=20;
damage+=4;
break;
case RawMaterial.RESOURCE_GRANITE:
case RawMaterial.RESOURCE_OBSIDIAN:
case RawMaterial.RESOURCE_IRONWOOD:
baseattack+=10;
damage+=2;
break;
case RawMaterial.RESOURCE_SAND:
case RawMaterial.RESOURCE_COAL:
baseattack-=40;
damage-=8;
break;
}
}
if(basematerial==RawMaterial.MATERIAL_WOODEN)
{
switch(material&RawMaterial.MATERIAL_MASK)
{
case RawMaterial.MATERIAL_WOODEN:
case RawMaterial.MATERIAL_ENERGY:
break;
case RawMaterial.MATERIAL_METAL:
case RawMaterial.MATERIAL_MITHRIL:
damage+=2;
baseattack-=0;
break;
case RawMaterial.MATERIAL_PRECIOUS:
damage+=2;
baseattack-=10;
break;
case RawMaterial.MATERIAL_LEATHER:
case RawMaterial.MATERIAL_SYNTHETIC:
damage-=2;
baseattack-=0;
break;
case RawMaterial.MATERIAL_ROCK:
damage+=2;
baseattack-=10;
break;
case RawMaterial.MATERIAL_GLASS:
damage-=2;
baseattack-=10;
break;
default:
damage-=6;
baseattack-=30;
break;
}
switch(material)
{
case RawMaterial.RESOURCE_LIMESTONE:
case RawMaterial.RESOURCE_FLINT:
baseattack-=10;
damage-=2;
break;
case RawMaterial.RESOURCE_CLAY:
baseattack-=20;
damage-=4;
break;
case RawMaterial.RESOURCE_BONE:
baseattack+=20;
damage+=4;
break;
case RawMaterial.RESOURCE_GRANITE:
case RawMaterial.RESOURCE_OBSIDIAN:
baseattack+=10;
damage+=2;
break;
case RawMaterial.RESOURCE_SAND:
case RawMaterial.RESOURCE_COAL:
baseattack-=40;
damage-=8;
break;
}
}
if(damage<=0)
damage=1;
vals.put("DAMAGE",""+damage);
vals.put("ATTACK",""+baseattack);
vals.put("VALUE",""+cost);
}
else
if(I instanceof Armor)
{
final int[] leatherPoints={ 0, 0, 1, 5,10,16,23,31,40,49,58,67,76,85,94};
final int[] clothPoints= { 0, 3, 7,12,18,25,33,42,52,62,72,82,92,102};
final int[] metalPoints= { 0, 0, 0, 0, 1, 3, 5, 8,12,17,23,30,38,46,54,62,70,78,86,94};
double pts=0.0;
if(level<0)
level=0;
final int materialCode=material&RawMaterial.MATERIAL_MASK;
int[] useArray=null;
switch(materialCode)
{
case RawMaterial.MATERIAL_METAL:
case RawMaterial.MATERIAL_MITHRIL:
case RawMaterial.MATERIAL_PRECIOUS:
case RawMaterial.MATERIAL_ENERGY:
useArray=metalPoints;
break;
case RawMaterial.MATERIAL_SYNTHETIC:
case RawMaterial.MATERIAL_LEATHER:
case RawMaterial.MATERIAL_GLASS:
case RawMaterial.MATERIAL_ROCK:
case RawMaterial.MATERIAL_WOODEN:
useArray=leatherPoints;
break;
default:
useArray=clothPoints;
break;
}
if(level>=useArray[useArray.length-1])
pts=useArray.length-2;
else
for(int i=0;i<useArray.length;i++)
{
final int lvl=useArray[i];
if(lvl>level)
{
pts=i-1;
break;
}
}
double totalpts=0.0;
double weightpts=0.0;
final Wearable.CODES codes = Wearable.CODES.instance();
for(int i=0;i<codes.location_strength_points().length-1;i++)
{
if(CMath.isSet(worndata,i))
{
totalpts+=(pts*codes.location_strength_points()[i+1]);
switch(materialCode)
{
case RawMaterial.MATERIAL_METAL:
case RawMaterial.MATERIAL_MITHRIL:
case RawMaterial.MATERIAL_PRECIOUS:
weightpts+=codes.material_weight_item()[i+1][2];
break;
case RawMaterial.MATERIAL_LEATHER:
case RawMaterial.MATERIAL_GLASS:
case RawMaterial.MATERIAL_SYNTHETIC:
case RawMaterial.MATERIAL_ROCK:
case RawMaterial.MATERIAL_WOODEN:
weightpts+=codes.material_weight_item()[i+1][1];
break;
case RawMaterial.MATERIAL_ENERGY:
break;
default:
weightpts+=codes.material_weight_item()[i+1][0];
break;
}
if(hands==1)
break;
}
}
final int cost=(int)Math.round(((pts*pts) + materialvalue) * ( weightpts / 2.0));
int armor=(int)Math.round(totalpts);
switch(material)
{
case RawMaterial.RESOURCE_BALSA:
case RawMaterial.RESOURCE_LIMESTONE:
case RawMaterial.RESOURCE_FLINT:
armor-=1;
break;
case RawMaterial.RESOURCE_CLAY:
armor-=2;
break;
case RawMaterial.RESOURCE_BONE:
armor+=2;
break;
case RawMaterial.RESOURCE_GRANITE:
case RawMaterial.RESOURCE_OBSIDIAN:
case RawMaterial.RESOURCE_IRONWOOD:
armor+=1;
break;
case RawMaterial.RESOURCE_SAND:
case RawMaterial.RESOURCE_COAL:
armor-=4;
break;
}
vals.put("ARMOR",""+armor);
vals.put("VALUE",""+cost);
vals.put("WEIGHT",""+(int)Math.round(weightpts));
}
return vals;
}
@Override
public void toneDownWeapon(final Weapon W, final Ability adjA)
{
if(adjA!=null)
{
final String oldTxt=adjA.text();
adjA.setStat("TONEDOWN-WEAPON", "90%");
if(!adjA.text().equals(oldTxt))
{
W.recoverPhyStats();
return;
}
}
if(W.basePhyStats().damage()>=10)
W.basePhyStats().setDamage((int)Math.round(CMath.mul(W.basePhyStats().damage(),0.9)));
else
if(W.basePhyStats().damage()>1)
W.basePhyStats().setDamage(W.basePhyStats().damage()-1);
if(W.basePhyStats().attackAdjustment()>=10)
W.basePhyStats().setAttackAdjustment((int)Math.round(CMath.mul(W.basePhyStats().attackAdjustment(),0.9)));
else
if(W.basePhyStats().attackAdjustment()>1)
W.basePhyStats().setAttackAdjustment(W.basePhyStats().attackAdjustment()-1);
W.recoverPhyStats();
}
@Override
public void toneDownArmor(final Armor A, final Ability adjA)
{
boolean fixit=true;
if(adjA!=null)
{
final String oldTxt=adjA.text();
adjA.setStat("TONEDOWN-ARMOR", "90%");
if(!adjA.text().equals(oldTxt))
fixit=false;
}
if(fixit&&(A.basePhyStats().armor()>=10))
A.basePhyStats().setArmor((int)Math.round(CMath.mul(A.basePhyStats().armor(),0.9)));
else
if(fixit&&(A.basePhyStats().armor()>1))
A.basePhyStats().setArmor(A.basePhyStats().armor()-1);
A.recoverPhyStats();
}
public Map<Object,Integer> getItemLevels(final Item I, final List<Ability> props)
{
final Map<Object,Integer> map=new HashMap<Object,Integer>();
map.put(I,Integer.valueOf(timsBaseLevel(I,this.getBaseAdjusterAbility(props))));
map.put("ABILITY",Integer.valueOf(levelsFromAbility(I)));
for(final Ability A : props)
map.put(A, Integer.valueOf(CMath.s_int(A.getStat("STAT-LEVEL"))));
return map;
}
public int totalLevels(final Map<Object,Integer> totalLevels)
{
int lvl=0;
for(final Integer I : totalLevels.values())
lvl += I.intValue();
return lvl;
}
public Ability getBaseAdjusterAbility(final List<Ability> props)
{
final String[] stats=new String[] {"STAT-ARMOR", "STAT-ATTACK", "STAT-DAMAGE"};
for(final Ability A : props)
{
if(CMath.bset(A.flags(), Ability.FLAG_ADJUSTER))
{
for(final String stat : stats)
{
final String val=A.getStat(stat);
if((val.length()>0)&&(!val.equals("0")))
return A;
}
}
}
return null;
}
@Override
public int timsBaseLevel(final Item I)
{
final List<Ability> props=getTimsAdjResCast(I);
return timsBaseLevel(I,getBaseAdjusterAbility(props));
}
public int timsBaseLevel(final Item I, final Ability adjA)
{
int level=0;
int otherDam=0;
int otherAtt=0;
int otherArm=0;
if(adjA!=null)
{
otherArm=-CMath.s_int(adjA.getStat("STAT-ARMOR"));
otherAtt=CMath.s_int(adjA.getStat("STAT-ATTACK"));
otherDam=CMath.s_int(adjA.getStat("STAT-DAMAGE"));
}
final int curArmor=I.basePhyStats().armor()+otherArm;
final double curAttack=I.basePhyStats().attackAdjustment()+otherAtt;
final double curDamage=I.basePhyStats().damage()+otherDam;
if(I instanceof Weapon)
{
double weight=8;
if(weight<1.0)
weight=1.0;
final double range=((Weapon)I).getRanges()[1];
final int wclass = ((Weapon)I).weaponClassification();
final double dmgMod = this.timsDmgModifier(wclass);
final double dmgLevel = Math.floor(((2.0*curDamage/(2.0*(I.rawLogicalAnd()?2.0:1.0)+1.0)+(curAttack-weight)/5.0+range)*(range/weight+2.0)/dmgMod))+1;
final double baseAttack = (curAttack - timsBaseAttackModifier(wclass));
double attackLevel;
if(baseAttack < 0)
attackLevel = dmgLevel - baseAttack;
else
if(this.timsAttackModifier(wclass)>0.0)
attackLevel = baseAttack / this.timsAttackModifier(wclass);
else
attackLevel = dmgLevel + baseAttack;
level = (int)Math.round((dmgLevel + attackLevel) / 2.0);
}
else
{
final long worndata=I.rawProperLocationBitmap();
double weightpts=0;
final Wearable.CODES codes = Wearable.CODES.instance();
for(int i=0;i<codes.location_strength_points().length-1;i++)
{
if(CMath.isSet(worndata,i))
{
weightpts+=codes.location_strength_points()[i+1];
if(!I.rawLogicalAnd())
break;
}
}
final int[] leatherPoints={ 0, 0, 1, 5,10,16,23,31,40,49,58,67,76,85,94};
final int[] clothPoints= { 0, 3, 7,12,18,25,33,42,52,62,72,82,92,102};
final int[] metalPoints= { 0, 0, 0, 0, 1, 3, 5, 8,12,17,23,30,38,46,54,62,70,78,86,94};
final int materialCode=I.material()&RawMaterial.MATERIAL_MASK;
int[] useArray=null;
switch(materialCode)
{
case RawMaterial.MATERIAL_METAL:
case RawMaterial.MATERIAL_MITHRIL:
case RawMaterial.MATERIAL_PRECIOUS:
case RawMaterial.MATERIAL_ENERGY:
useArray=metalPoints;
break;
case RawMaterial.MATERIAL_SYNTHETIC:
case RawMaterial.MATERIAL_LEATHER:
case RawMaterial.MATERIAL_GLASS:
case RawMaterial.MATERIAL_ROCK:
case RawMaterial.MATERIAL_WOODEN:
useArray=leatherPoints;
break;
case RawMaterial.MATERIAL_GAS:
default:
useArray=clothPoints;
break;
}
int which=(int)Math.round(CMath.div(curArmor,weightpts)+1);
if(which<0)
which=0;
if(which>=useArray.length)
which=useArray.length-1;
level=useArray[which];
}
if(!CMLib.flags().isRemovable(I))
level-=5;
return level;
}
protected int levelsFromAbility(final Item savedI)
{
return savedI.basePhyStats().ability() * 5;
}
@SuppressWarnings("unchecked")
public synchronized List<Ability> getCombatSpellSet()
{
List<Ability> spellSet=(List<Ability>)Resources.getResource("COMPLETE_SPELL_SET");
if(spellSet==null)
{
spellSet=new Vector<Ability>();
Ability A=null;
for(final Enumeration<Ability> e=CMClass.abilities();e.hasMoreElements();)
{
A=e.nextElement();
if(((A.classificationCode()&(Ability.ALL_ACODES))==Ability.ACODE_SPELL))
{
final int lowLevel=CMLib.ableMapper().lowestQualifyingLevel(A.ID());
if((lowLevel>0)&&(lowLevel<25))
spellSet.add(A);
}
}
Resources.submitResource("COMPLETE_SPELL_SET",spellSet);
}
return spellSet;
}
public Ability getCombatSpell(final boolean malicious)
{
final List<Ability> spellSet=getCombatSpellSet();
int tries=0;
while(((++tries)<1000))
{
final Ability A=spellSet.get(CMLib.dice().roll(1,spellSet.size(),-1));
if(((malicious)&&(A.canTarget(Ability.CAN_MOBS))&&(A.enchantQuality()==Ability.QUALITY_MALICIOUS)))
return A;
if((!malicious)
&&(A.canAffect(Ability.CAN_MOBS))
&&(A.enchantQuality()!=Ability.QUALITY_MALICIOUS)
&&(A.enchantQuality()!=Ability.QUALITY_INDIFFERENT))
return A;
}
return null;
}
@Override
public Item enchant(final Item I, final int pct)
{
if(CMLib.dice().rollPercentage()>pct)
return I;
int bump=0;
while((CMLib.dice().rollPercentage()<=10)||(bump==0))
bump=bump+((CMLib.dice().rollPercentage()<=80)?1:-1);
if(bump<0)
CMLib.flags().setRemovable(I,false);
I.basePhyStats().setDisposition(I.basePhyStats().disposition()|PhyStats.IS_BONUS);
I.recoverPhyStats();
if(I instanceof Ammunition)
{
int lvlChange=bump*3;
if(lvlChange<0)
lvlChange=lvlChange*-1;
I.basePhyStats().setLevel(I.basePhyStats().level()+lvlChange);
switch(CMLib.dice().roll(1,2,0))
{
case 1:
{
final Ability A=CMClass.getAbility("Prop_WearAdjuster");
if(A==null)
return I;
A.setMiscText("att"+((bump<0)?"":"+")+(bump*5)+" dam="+((bump<0)?"":"+")+bump);
I.addNonUninvokableEffect(A);
break;
}
case 2:
{
Ability A=null;
if(bump<0)
A=CMClass.getAbility("Prayer_CurseItem");
else
{
A=CMClass.getAbility("Prop_FightSpellCast");
if(A!=null)
for(int a=0;a<bump;a++)
{
final Ability A2=getCombatSpell(true);
if(A2!=null)
A.setMiscText(A.text()+";"+A2.ID());
}
}
if(A==null)
return I;
I.addNonUninvokableEffect(A);
break;
}
}
I.recoverPhyStats();
}
else
if(I instanceof Weapon)
{
switch(CMLib.dice().roll(1,2,0))
{
case 1:
{
I.basePhyStats().setAbility(bump);
break;
}
case 2:
{
Ability A=null;
if(bump<0)
A=CMClass.getAbility("Prayer_CurseItem");
else
{
A=CMClass.getAbility("Prop_FightSpellCast");
if(A!=null)
{
for(int a=0;a<bump;a++)
{
final Ability A2=getCombatSpell(true);
if(A2!=null)
A.setMiscText(A.text()+";"+A2.ID());
}
I.basePhyStats().setLevel(I.basePhyStats().level()+CMath.s_int(A.getStat("STAT-LEVEL")));
}
}
if(A==null)
return I;
I.addNonUninvokableEffect(A);
break;
}
}
I.recoverPhyStats();
}
else
if(I instanceof Armor)
{
switch(CMLib.dice().roll(1,2,0))
{
case 1:
{
I.basePhyStats().setAbility(bump);
break;
}
case 2:
{
Ability A=null;
if(bump<0)
A=CMClass.getAbility("Prayer_CurseItem");
else
{
A=CMClass.getAbility("Prop_WearSpellCast");
if(A!=null)
{
for(int a=0;a<bump;a++)
{
final Ability A2=getCombatSpell(false);
if(A2!=null)
A.setMiscText(A.text()+";"+A2.ID());
}
I.basePhyStats().setLevel(I.basePhyStats().level()+CMath.s_int(A.getStat("STAT-LEVEL")));
}
}
if(A==null)
return I;
I.addNonUninvokableEffect(A);
break;
}
}
I.recoverPhyStats();
}
return I;
}
}