Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Server Code Submissions

Reply
 
Thread Tools Display Modes
  #1  
Old 11-10-2010, 02:10 PM
bad_captain
Developer
 
Join Date: Feb 2009
Location: Cincinnati, OH
Posts: 512
Default Bot AC Fix

I have rewritten how Bot AC is calculated to emulate Client AC. I've wondered for a while why my Warrior Bot MT had only ~100 more AC than my Magician, and have found the reason. Basically, Bots were getting negligible base AC from level and AGI, and 0 from defense skill. Almost all AC was from equipment and spells.

I did a test last night leveling up a new toon from 1 to 65, both by using #level 65 and #setxp going up to 65, then updating my Bot. Using #level 65, the Bot was left with a base AC of 40 (40 AC at level 65 for a Warrior!). If I used #setxp, leveling up, then updating my Bot, the AC went up with the levels, but maxed at around 200. When the Bot was camped and respawned, it respawned with only 40 AC. Obviously this is not correct.

Using the below code, my Warrior Bot went from ~1200 AC buffed to 1450 AC unbuffed, which matches what magelo.com reports is should be (I created a few toons there by hand a while ago to be able to check these things). Note - Bot stats suffer from double adding of stats from items and spells, including AC, which throws many calculations off. The above AC has been adjusted, taking this into account. My Warrior shows a STR in game of 850 with buffs, wearing a mix of Ornate, VT, pre-EP gear. This is approximately double what it should be (Magelo says it should be 326 unbuffed). I believe I have found the source of this issue, but will need to test it out the next couple of days, so I will go head and post this now. This code will be unchanged by the fix for double stats, except for the actual ingame calculations done with this code.

bot.h
Code:
--- EQEmuServer\zone\bot.h	Tue Nov  9 23:56:21 2010
+++ C:\EqEmuSource\EQEmuServer\zone\bot.h	Mon Nov  8 22:01:27 2010
@@ -263,6 +263,7 @@
 	bool GetRangerAutoWeaponSelect() { return _rangerAutoWeaponSelect; }
 	BotRoleType GetBotRole() { return _botRole; }
 	bool IsBotCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == NECROMANCER || GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == ENCHANTER); }
+	int16 MaxSkill(SkillType skillid, int16 class_, int16 level) const;
 
 	// "SET" Class Methods
 	void SetBotSpellID(uint32 newSpellID);
@@ -323,6 +324,7 @@
 	sint16 _baseFR;
 	sint16 _basePR;
 	int _baseAC;
+	int16 _baseDefense;
 	sint16 _baseSTR;
 	sint16 _baseSTA;
 	sint16 _baseDEX;
@@ -335,8 +337,10 @@
 	int8 _baseGender;	// Bots gender. Necessary to preserve the original value otherwise it can be changed by illusions.
 
 	// Class Methods
+	sint16 acmod();
 	void GenerateBaseStats();
 	void GenerateAppearance();
+	void GenerateBaseDefense();
 	void GenerateArmorClass();
 	void GenerateBaseHitPoints();
 	void GenerateAABonuses();


bot.cpp
Code:
--- EQEmuServer\zone\bot.cpp	Tue Nov  9 23:56:35 2010
+++ C:\EqEmuSource\EQEmuServer\zone\bot.cpp	Tue Nov  9 23:55:49 2010
@@ -53,6 +53,7 @@
 	GenerateAppearance();
 
 	GenerateBaseStats();
+	GenerateBaseDefense();
 	GenerateArmorClass();
 
 	// Calculate HitPoints Last As It Uses Base Stats
@@ -118,6 +119,7 @@
 	}
 
 	GenerateBaseStats();
+	GenerateBaseDefense();
 	GenerateArmorClass();
 
 	// Calculate HitPoints Last As It Uses Base Stats
@@ -757,17 +759,422 @@
 
 }
 
+int16 Bot::MaxSkill(SkillType skillid, int16 class_, int16 level) const {
+	return(database.GetSkillCap(class_, skillid, level));
+}
+
+sint16 Bot::acmod() {
+	int agility = GetAGI();
+	int level = GetLevel();
+	if(agility < 1 || level < 1)
+		return(0);
+	
+	if (agility <=74){
+		if (agility == 1)
+			return -24;
+		else if (agility <=3)
+			return -23;
+		else if (agility == 4)
+			return -22;
+		else if (agility <=6)
+			return -21;
+		else if (agility <=8)
+			return -20;
+		else if (agility == 9)
+			return -19;
+		else if (agility <=11)
+			return -18;
+		else if (agility == 12)
+			return -17;
+		else if (agility <=14)
+			return -16;
+		else if (agility <=16)
+			return -15;
+		else if (agility == 17)
+			return -14;
+		else if (agility <=19)
+			return -13;
+		else if (agility == 20)
+			return -12;
+		else if (agility <=22)
+			return -11;
+		else if (agility <=24)
+			return -10;
+		else if (agility == 25)
+			return -9;
+		else if (agility <=27)
+			return -8;
+		else if (agility == 28)
+			return -7;
+		else if (agility <=30)
+			return -6;
+		else if (agility <=32)
+			return -5;
+		else if (agility == 33)
+			return -4;
+		else if (agility <=35)
+			return -3;
+		else if (agility == 36)
+			return -2;
+		else if (agility <=38)
+			return -1;
+		else if (agility <=65)
+			return 0;
+		else if (agility <=70)
+			return 1;
+		else if (agility <=74)
+			return 5;
+	}
+	else if(agility <= 137) {
+		if (agility == 75){
+			if (level <= 6)
+				return 9;
+			else if (level <= 19)
+				return 23;
+			else if (level <= 39)
+				return 33;
+			else
+				return 39;
+		}
+		else if (agility >= 76 && agility <= 79){
+			if (level <= 6)
+				return 10;
+			else if (level <= 19)
+				return 23;
+			else if (level <= 39)
+				return 33;
+			else
+				return 40;
+		}
+		else if (agility == 80){
+			if (level <= 6)
+				return 11;
+			else if (level <= 19)
+				return 24;
+			else if (level <= 39)
+				return 34;
+			else
+				return 41;
+		}
+		else if (agility >= 81 && agility <= 85){
+			if (level <= 6)
+				return 12;
+			else if (level <= 19)
+				return 25;
+			else if (level <= 39)
+				return 35;
+			else
+				return 42;
+		}
+		else if (agility >= 86 && agility <= 90){
+			if (level <= 6)
+				return 12;
+			else if (level <= 19)
+				return 26;
+			else if (level <= 39)
+				return 36;
+			else
+				return 42;
+		}
+		else if (agility >= 91 && agility <= 95){
+			if (level <= 6)
+				return 13;
+			else if (level <= 19)
+				return 26;
+			else if (level <= 39)
+				return 36;
+			else
+				return 43;
+		}
+		else if (agility >= 96 && agility <= 99){
+			if (level <= 6)
+				return 14;
+			else if (level <= 19)
+				return 27;
+			else if (level <= 39)
+				return 37;
+			else 
+				return 44;
+		}
+		else if (agility == 100 && level >= 7){
+			if (level <= 19)
+				return 28;
+			else if (level <= 39)
+				return 38;
+			else
+				return 45;
+		}
+		else if (level <= 6) {
+			return 15;
+		}
+		//level is >6
+		else if (agility >= 101 && agility <= 105){
+			if (level <= 19)
+				return 29;
+			else if (level <= 39)
+				return 39;// not verified
+			else
+				return 45;
+		}
+		else if (agility >= 106 && agility <= 110){
+			if (level <= 19)
+				return 29;
+			else if (level <= 39)
+				return 39;// not verified
+			else
+				return 46;
+		}
+		else if (agility >= 111 && agility <= 115){
+			if (level <= 19)
+				return 30;
+			else if (level <= 39)
+				return 40;// not verified
+			else
+				return 47;
+		}
+		else if (agility >= 116 && agility <= 119){
+			if (level <= 19)
+				return 31;
+			else if (level <= 39)
+				return 41;
+			else
+				return 47;
+		}
+		else if (level <= 19) {
+				return 32;
+		}
+		//level is > 19
+		else if (agility == 120){
+			if (level <= 39)
+				return 42;
+			else
+				return 48;
+		}
+		else if (agility <= 125){
+			if (level <= 39)
+				return 42;
+			else
+				return 49;
+		}
+		else if (agility <= 135){
+			if (level <= 39)
+				return 42;
+			else
+				return 50;
+		}
+		else {
+			if (level <= 39)
+				return 42;
+			else
+				return 51;
+		}
+	} else if(agility <= 300) {
+		if(level <= 6) {
+			if(agility <= 139)
+				return(21);
+			else if(agility == 140)
+				return(22);
+			else if(agility <= 145)
+				return(23);
+			else if(agility <= 150)
+				return(23);
+			else if(agility <= 155)
+				return(24);
+			else if(agility <= 159)
+				return(25);
+			else if(agility == 160)
+				return(26);
+			else if(agility <= 165)
+				return(26);
+			else if(agility <= 170)
+				return(27);
+			else if(agility <= 175)
+				return(28);
+			else if(agility <= 179)
+				return(28);
+			else if(agility == 180)
+				return(29);
+			else if(agility <= 185)
+				return(30);
+			else if(agility <= 190)
+				return(31);
+			else if(agility <= 195)
+				return(31);
+			else if(agility <= 199)
+				return(32);
+			else if(agility <= 219)
+				return(33);
+			else if(agility <= 239)
+				return(34);
+			else
+				return(35);
+		} else if(level <= 19) {
+			if(agility <= 139)
+				return(34);
+			else if(agility == 140)
+				return(35);
+			else if(agility <= 145)
+				return(36);
+			else if(agility <= 150)
+				return(37);
+			else if(agility <= 155)
+				return(37);
+			else if(agility <= 159)
+				return(38);
+			else if(agility == 160)
+				return(39);
+			else if(agility <= 165)
+				return(40);
+			else if(agility <= 170)
+				return(40);
+			else if(agility <= 175)
+				return(41);
+			else if(agility <= 179)
+				return(42);
+			else if(agility == 180)
+				return(43);
+			else if(agility <= 185)
+				return(43);
+			else if(agility <= 190)
+				return(44);
+			else if(agility <= 195)
+				return(45);
+			else if(agility <= 199)
+				return(45);
+			else if(agility <= 219)
+				return(46);
+			else if(agility <= 239)
+				return(47);
+			else
+				return(48);
+		} else if(level <= 39) {
+			if(agility <= 139)
+				return(44);
+			else if(agility == 140)
+				return(45);
+			else if(agility <= 145)
+				return(46);
+			else if(agility <= 150)
+				return(47);
+			else if(agility <= 155)
+				return(47);
+			else if(agility <= 159)
+				return(48);
+			else if(agility == 160)
+				return(49);
+			else if(agility <= 165)
+				return(50);
+			else if(agility <= 170)
+				return(50);
+			else if(agility <= 175)
+				return(51);
+			else if(agility <= 179)
+				return(52);
+			else if(agility == 180)
+				return(53);
+			else if(agility <= 185)
+				return(53);
+			else if(agility <= 190)
+				return(54);
+			else if(agility <= 195)
+				return(55);
+			else if(agility <= 199)
+				return(55);
+			else if(agility <= 219)
+				return(56);
+			else if(agility <= 239)
+				return(57);
+			else
+				return(58);
+		} else {	//lvl >= 40
+			if(agility <= 139)
+				return(51);
+			else if(agility == 140)
+				return(52);
+			else if(agility <= 145)
+				return(53);
+			else if(agility <= 150)
+				return(53);
+			else if(agility <= 155)
+				return(54);
+			else if(agility <= 159)
+				return(55);
+			else if(agility == 160)
+				return(56);
+			else if(agility <= 165)
+				return(56);
+			else if(agility <= 170)
+				return(57);
+			else if(agility <= 175)
+				return(58);
+			else if(agility <= 179)
+				return(58);
+			else if(agility == 180)
+				return(59);
+			else if(agility <= 185)
+				return(60);
+			else if(agility <= 190)
+				return(61);
+			else if(agility <= 195)
+				return(61);
+			else if(agility <= 199)
+				return(62);
+			else if(agility <= 219)
+				return(63);
+			else if(agility <= 239)
+				return(64);
+			else
+				return(65);
+		}
+	}
+	else{
+		//seems about 21 agil per extra AC pt over 300...
+	return (65 + ((agility-300) / 21));
+	}
+#if EQDEBUG >= 11
+	LogFile->write(EQEMuLog::Error, "Error in Bot::acmod(): Agility: %i, Level: %i",agility,level);
+#endif
+	return 0;
+};
+
+void Bot::GenerateBaseDefense() {
+	_baseDefense = MaxSkill(DEFENSE, GetClass(), GetLevel());
+}
+
 void Bot::GenerateArmorClass() {
-	// Base AC
-	int bac = GetAC();
-	switch(this->GetClass()) {
-			case WARRIOR:
-			case SHADOWKNIGHT:
-			case PALADIN:
-				bac = bac*1.5;
+	/// new formula
+	int avoidance = 0;
+	avoidance = (acmod() + ((_baseDefense*16)/9));
+	if (avoidance < 0)
+		avoidance = 0;
+
+	int mitigation = 0;
+	if (GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER) {
+		mitigation = _baseDefense/4 + (itembonuses.AC+1);
+		mitigation -= 4;
+	} else {
+		mitigation = _baseDefense/3 + ((itembonuses.AC*4)/3);
+		if(GetClass() == MONK)
+			mitigation += GetLevel() * 13/10;	//the 13/10 might be wrong, but it is close...
 	}
+	int displayed = 0;
+	displayed += ((avoidance+mitigation)*1000)/847;	//natural AC
+	
+	//Iksar AC, untested
+	if (GetRace() == IKSAR) {
+		displayed += 12;
+		int iksarlevel = GetLevel();
+		iksarlevel -= 10;
+		if (iksarlevel > 25)
+			iksarlevel = 25;
+		if (iksarlevel > 0)
+			displayed += iksarlevel * 12 / 10;
+	}
+	
+	//spell AC bonuses are added directly to natural total
+	displayed += spellbonuses.AC;  
 
-	this->AC = bac;
+	this->AC = displayed;
 }
 
 void Bot::GenerateBaseHitPoints() {
@@ -8626,8 +9033,6 @@
 
 	GenerateAABonuses();
 
-	GenerateArmorClass();
-
 	//// Calc Base Hit Points
 	//int16 lm = GetClassLevelFactor();
 	//int16 Post255;
@@ -8798,7 +9203,7 @@
 	DR += itembonuses.DR;
 	FR += itembonuses.FR;
 	PR += itembonuses.PR;
-	AC += itembonuses.AC;
+	//AC += itembonuses.AC;
 	STR += itembonuses.STR;
 	STA += itembonuses.STA;
 	DEX += itembonuses.DEX;
@@ -8813,7 +9218,7 @@
 	DR += spellbonuses.DR;
 	FR += spellbonuses.FR;
 	PR += spellbonuses.PR;
-	AC += spellbonuses.AC;
+	//AC += spellbonuses.AC;
 	STR += spellbonuses.STR;
 	STA += spellbonuses.STA;
 	DEX += spellbonuses.DEX;
@@ -8823,6 +9228,8 @@
 	CHA += spellbonuses.CHA;
 	ATK += spellbonuses.ATK;
 
+	GenerateBaseDefense();
+	GenerateArmorClass();
 	cur_hp = CalcMaxHP();
 	GenerateBaseManaPoints();
 	
@@ -9582,6 +9989,7 @@
 				//bot->SetLevel(c->GetLevel());
 				bot->SetPetChooser(false);
 				bot->CalcBotStats();
+				bot->GenerateBaseDefense();
 			}
 			else {
 				if(c->GetFeigned()) {
Reply With Quote
  #2  
Old 11-10-2010, 04:10 PM
Congdar
Developer
 
Join Date: Jul 2007
Location: my own little world
Posts: 751
Default

I appreciate these bot fix submissions. Wildcardx started a branch to rewrite the bot code, so these may be moot fixes and I was gonna post to wait for his rewrite before making more submissions.
Last time he updated the bots and new fixes were added, they were dropped and didn't get in. So this time I was not going to add any new updates. Now he's dissappeared and hasn't done anything in a while, so I'm starting to think about adding these submissions in again. I'm going on vacation, and when I get back I'll see if he's done more work on the new mercs/bots. If not I can see about getting these submissoins added.
__________________
The Realm
Reply With Quote
  #3  
Old 11-10-2010, 04:21 PM
bad_captain
Developer
 
Join Date: Feb 2009
Location: Cincinnati, OH
Posts: 512
Default

Yeah, I talked to him once in the week or so he was back about some bot spell stuff I'm working on, and was going to wait see how things progressed on his work on mercs/bots before bringing some of these things up. But since he's not been around again, and it seemed like all of the merc changes were going to take a while anyway, I figured I would go ahead and submit them. I'll post a single submission with all of the changes as soon as I test the double stat fix I made.

I'm trying to progress into the elemental planes on my own server, and some of these changes are needed for my bots to live up to the pounding they are going to take. I figure if they even help out for a few months for someone besides me, it's worth it.
Reply With Quote
  #4  
Old 11-11-2010, 09:53 AM
bad_captain
Developer
 
Join Date: Feb 2009
Location: Cincinnati, OH
Posts: 512
Default

Re: Double stats on bots- I found the issue and fixed it, but need to retest again tonight before submitting it all. Basically, in CalcBotStats, the item and spell bonuses were added, but then in Get[Stat]() functions, the base stat was returned, plus item and spell bonuses. I found a couple of places where the actual stat variable was used instead of Get[Stat](), which was then not adding in item and spell bonuses, so I will change those, then I think the stats will be fixed.

Possible other issues I will look into- ATK seems to be calculated differently from clients (I don't think Offense is used), and adding in stat caps (even without double stats, by WAR has like 650 STR).

Last edited by bad_captain; 11-11-2010 at 10:34 AM.. Reason: Added explanation as to how stats were doubled.
Reply With Quote
  #5  
Old 11-15-2010, 10:33 AM
bad_captain
Developer
 
Join Date: Feb 2009
Location: Cincinnati, OH
Posts: 512
Default

Later this week, I will be posting a consolidated post with multiple fixes including this one.

Fixed double stats, stats caps, and a couple other things. Once I fix a display bug for haste, and spell regen not working, I'll post.
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 02:56 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3