It's quite peculiar that you find that the Defense skill lowers damage taken in melee combat, because the Defense skill is not used in any melee damage calculation.
The only skills used in melee damage calculations are Melee and Luck.
From LAi_fightparams:
Code:
float LAi_BladeApplySkills(aref attack, aref enemy, float dmg)
{
//Ó÷èòûâàåì ñêèëû
float aSkill = LAi_GetCharacterFightLevel(attack);
float eSkill = LAi_GetCharacterFightLevel(enemy);
if(aSkill >= eSkill)
{
dmg = dmg*(1.0 + 2.0*(aSkill - eSkill));
}else{
dmg = dmg*(1.0 + 0.5*(aSkill - eSkill));
}
// NK -->
dmg *= (0.75 + fRand(GetSummonSkill(attack, SKILL_SNEAK))/(40.0/3.0));
dmg *= (1.5 - fRand(GetSummonSkill(enemy, SKILL_SNEAK))/(40.0/3.0));
float piercing = 0.05;
float block = 0.01;
if(CheckAttribute(attack, "chr_ai.piercing"))
{
piercing = stf(attack.chr_ai.piercing);
}
if(CheckAttribute(enemy, "chr_ai.block"))
{
block = stf(enemy.chr_ai.block);
}
if(piercing > block*2 && piercing > 0.1) dmg *= (1.0 + fRand(piercing)/2.0);
if(sti(attack.index) == GetMainCharacterIndex()) dmg *= (1.45 - 0.15*GetDifficulty()); // NK Diff Mod
else { if(sti(enemy.index) == GetMainCharacterIndex()) { dmg *= (0.85 + 0.15*GetDifficulty()); } } // NK Diff Mod
// NK <--
return dmg;
}
Here we see that "FightLevel" and Luck ("Sneak" is Luck in the code) are used. FightLevel is defined in LAi_utils:
Code:
float LAi_GetCharacterFightLevel(aref character)
{
//Fencing skill
float fgtlevel = 0.0;
if(isBoardingLoading == false)
{
if(CheckAttribute(character, "skill.Fencing") != 0)
{
fgtlevel = makefloat(GetCharacterSkill(character,SKILL_FENCING)); // NK
}
}else{
fgtlevel = GetSummonSkillFromName(character, SKILL_FENCING);
}
//Level
if(fgtlevel < 0.0) fgtlevel = 0.0;
if(fgtlevel > SKILL_MAX) fgtlevel = SKILL_MAX;
fgtlevel = fgtlevel/SKILL_MAX;
return fgtlevel;
}
Here we see that FightLevel is the character's Melee skill divided by the maximum skill value, which is 10.
Probability for piercing and blocking, again from LAi_fightparams:
Code:
float LAi_BladeFindPiercingProbability(aref attack, aref enemy, float hitDmg)
{
float piercing = 0.05;
float block = 0.01;
if(CheckAttribute(attack, "chr_ai.piercing"))
{
piercing = stf(attack.chr_ai.piercing); // 0..1 from blade stats
}
if(CheckAttribute(enemy, "chr_ai.block"))
{
block = stf(enemy.chr_ai.block); // 0..1 from blade stats
}
float aSkill = LAi_GetCharacterFightLevel(attack); // fencing skill / 10
float eSkill = LAi_GetCharacterFightLevel(enemy);
// LDH change to ratios - 11Apr09
// if(aSkill < eSkill) aSkill = eSkill; // NK had removed this and set p to minimum of 0
// float p = piercing - block + (aSkill - eSkill)*0.5; // original calculation
float origP = piercing - block + (floatret(aSkill<eSkill, eSkill, aSkill) - eSkill)*0.5; // LDH for testing 12Apr09
if (origP < 0.0) origP = 0.0;
// if (block == 0) block = 0.01;
// if (eSkill == 0) eSkill = 0.1;
// float p = sqrt(piercing/block * sqrt(aSkill/eSkill)); // pierce to block ratio * half skill ratio
// LDH - 01May09
float p = (1.0 + piercing - block)^10 * (1 + askill - eskill);
float k = 1.0;
if (p > 0) // LDH added test 06Apr09
{
if(IsCharacterPerkOn(enemy, "BasicDefense")) k = 0.75;
if(IsCharacterPerkOn(enemy, "AdvancedDefense")) k = 0.5;
}
hitDmg = hitDmg*0.5 + 0.5; // hitDmg is a small number, so this is 0.5 to 0.52 typically, can be higher
//float retVal = p*k*hitDmg*hitDmg*100; if (retVal > 100.0) retVal = 100.0;
//float retValOrig = origP*k*hitDmg*hitDmg*100;
//TraceAndLog("p=" + makeint(piercing*100) + ", " + stringRet(piercing<0.1," ","") +
// "b=" + makeint(block*100) + ", " + stringRet(block<0.1," ","") +
// "aSkill=" + makeint(aSkill*10) + ", " + stringRet(aSkill<1," ","") +
// "eSkill=" + makeint(eSkill*10) + ", " + stringRet(eSkill<1," ","") +
// "p=" + strLeft(f2s2(p*100),6) + ", " +
// "k=" + k + ", " + stringRet(k==1.0," ","") + stringRet(k==0.5," ","") +
// "hitDmg=" + strLeft(f2s2(hitDmg*hitDmg),6) + ", " +
// "return=" + strLeft(stringRet(retVal<10," ","") + f2s2(retVal),5) + ", " +
// "orig=" + stringRet(retValOrig==0,"",strLeft(f2s2(retValOrig),6)));
p = p*k*hitDmg*hitDmg;
if (p>1.0) p = 1.0;
return p;
}
The only thing referring to skills here is FightLevel, which we saw that the only skill it uses is the Melee skill.
The Defense skill is only used in ship damage calculations. From AIShip:
Code:
void Ship_ApplyCrewHitpoints(ref rOurCharacter, float fCrewHP)
{
// KK if(!CheckAttribute(rOurCharacter,"seatime.basecrewquantity")) rOurCharacter.ship.crew.quantity; // NK need to check 05-04-09
rOurCharacter.seatime.lasthit = GetSeaTime(); // NK 04-09-16, to set time when last hit
if(!CheckAttribute(rOurCharacter,"seatime.lastcrew")) rOurCharacter.seatime.lastcrew = rOurCharacter.ship.crew.quantity; // ditto, to set what crew was before loss
//ref rBaseShip = GetShipByType(GetCharacterShipType(&rOurCharacter));
float fMultiply;
float fskillDefence = stf(rOurCharacter.TmpSkill.Defence); // KK
int iskillDefence = GetCharacterSkill(rOurCharacter, "Defence"); // PB
if (USE_REAL_CANNONS)
fMultiply = Bring2Range(1.0, 0.5, 0.0, 1.0, fskillDefence); // KNB was from 1.0x to 0.2x damage
else
fMultiply = Bring2Range(1.0, 0.2, 0.0, 1.0, fskillDefence);
//NK -->
//aref arship; makearef(arship, rOurCharacter.ship); // PRS3
fMultiply *= (0.25 * (stf(rOurCharacter.Ship.Crew.Quantity) / makefloat(GetMinCrewQuantity(rOurCharacter)))); // PRS3
// NK <--
int casualties = makeint(fCrewHP * fMultiply); // PB
float fNewCrewQuantity = stf(rOurCharacter.Ship.Crew.Quantity) - casualties;
float f5Percent = makefloat(GetMinCrewQuantity(rOurCharacter)) * 0.05; // PRS3
if (fNewCrewQuantity < f5Percent) fNewCrewQuantity = f5Percent;
if (fNewCrewQuantity < 1.0) fNewCrewQuantity = 1.0;
// KK & PB -->
if (IsMainCharacter(rOurCharacter) || IsCompanion(rOurCharacter)) {
int wounded = casualties - randnorm(casualties, iskillDefence);
if (wounded > casualties) wounded = casualties;
if (wounded > 0) AddCharacterWoundedCrew(rOurCharacter, wounded);
else wounded = 0;
int killed_wounded;
if (rand( 3*iskillDefence ) == 1)
{
killed_wounded = 1;
RemoveCharacterWoundedCrew(rOurCharacter, 1);
}
else killed_wounded = 0;
trace("Ship_ApplyCrewHitpoints: casualties="+casualties+", iskillDefence="+iskillDefence +", wounded="+wounded +", killed_wounded="+killed_wounded);
}
SetCrewQuantity(rOurCharacter, fNewCrewQuantity);
// <-- KK & PB
}
So, as we can see, the Defense skill really isn't used in any melee damage calculation, only the Melee and Luck skills.
I searched for "ch.skill.Defence" and "SKILL_DEFENCE" but couldn't find any instance where the Defense skill is used for melee calculations. If I did indeed miss anything, please show me where the Defense skill is used for melee.
But! Note this part in the first code snippet:
Code:
if(sti(attack.index) == GetMainCharacterIndex()) dmg *= (1.45 - 0.15*GetDifficulty()); // NK Diff Mod
else { if(sti(enemy.index) == GetMainCharacterIndex()) { dmg *= (0.85 + 0.15*GetDifficulty()); } } // NK Diff Mod
Not only are Melee and Luck used for melee damage calculations, but difficulty as well. The higher the difficulty, you do less damage to enemies and they do more damage to you. This could be part of the reason why combat is hard.
Difficulty also affects the level, skills, and HP of enemies so with higher difficulty the enemies will be stronger than you with higher level, higher skills, higher HP, and so on. This could also contribute to combat being hard. As far as I understand, this is handled in LAi_CreateOfficer. Too much to quote from that file, but it's in there.
About some enemies attacking faster than other enemies, I believe this is handled under "NPC parameters" in LAi_fightparams. It also seems to handle how much they block and fire. Again FightLevel (and thus the Melee skill) and difficulty are used.
About blocking being changed so that it is not always working, what does that mean? Blocking does not always work as it is in the stock game. It is possible for blocks to be pierced depending on weapons used, the contenders' Melee skill, and which abilities they have.