Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Bug Reports

Development::Bug Reports Post detailed bug reports and what you would like to see next in the emu here.

Reply
 
Thread Tools Display Modes
  #1  
Old 07-26-2008, 10:50 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Well, I didn't have to add a new category after-all lol. I found the reason why my recast delays weren't working. It was because I was using recast timers similar to actual disc reuse timers. Some of them were 20 minutes or more. And in seconds, that is 1200.

I looked at recast delay settings in the source and I found this:

MobAI.cpp
Code:
void NPC::AI_Event_SpellCastFinished(bool iCastSucceeded, int8 slot) {
	if (slot == 1) {
		int32 recovery_time = 0;
		if (iCastSucceeded) {
			if (casting_spell_AIindex < MAX_AISPELLS) {
					recovery_time += spells[AIspells[casting_spell_AIindex].spellid].recovery_time;
					if (AIspells[casting_spell_AIindex].recast_delay >= 0){
						if (AIspells[casting_spell_AIindex].recast_delay <1000)
							AIspells[casting_spell_AIindex].time_cancast = Timer::GetCurrentTime() + (AIspells[casting_spell_AIindex].recast_delay*1000);
}
					else
						AIspells[casting_spell_AIindex].time_cancast = Timer::GetCurrentTime() + spells[AIspells[casting_spell_AIindex].spellid].recast_time;
			}
			if (!IsEngaged())
				recovery_time += RandomTimer(2000, 3000);
			if (recovery_time < AIautocastspell_timer->GetSetAtTrigger())
				recovery_time = AIautocastspell_timer->GetSetAtTrigger();
			AIautocastspell_timer->Start(recovery_time, false);
		}
		else
			AIautocastspell_timer->Start(800, false);
		casting_spell_AIindex = MAX_AISPELLS;
	}
}
And I simply changed the check for < 1000 to < 10000 and now my recast delays are working perfectly. Here is the change I made, highlighted in RED:

Code:
void NPC::AI_Event_SpellCastFinished(bool iCastSucceeded, int8 slot) {
	if (slot == 1) {
		int32 recovery_time = 0;
		if (iCastSucceeded) {
			if (casting_spell_AIindex < MAX_AISPELLS) {
					recovery_time += spells[AIspells[casting_spell_AIindex].spellid].recovery_time;
					if (AIspells[casting_spell_AIindex].recast_delay >= 0){
						if (AIspells[casting_spell_AIindex].recast_delay <10000)
							AIspells[casting_spell_AIindex].time_cancast = Timer::GetCurrentTime() + (AIspells[casting_spell_AIindex].recast_delay*1000);
}
					else
						AIspells[casting_spell_AIindex].time_cancast = Timer::GetCurrentTime() + spells[AIspells[casting_spell_AIindex].spellid].recast_time;
			}
			if (!IsEngaged())
				recovery_time += RandomTimer(2000, 3000);
			if (recovery_time < AIautocastspell_timer->GetSetAtTrigger())
				recovery_time = AIautocastspell_timer->GetSetAtTrigger();
			AIautocastspell_timer->Start(recovery_time, false);
		}
		else
			AIautocastspell_timer->Start(800, false);
		casting_spell_AIindex = MAX_AISPELLS;
	}
}
I don't see any reason why this couldn't be added to the source updates. I am not sure why the current limit was set to 1000 or less. I guess it wouldn't even apply in most cases, but disciplines for pets and NPC encounters that might last 20+ minutes could be effected by this.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #2  
Old 09-02-2008, 09:31 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Well, I am starting again to get the new spell type category working for NPCs. I haven't fully decided if I want to just make 1 new category or 2. I think Yaulp would be fine to set as a buff that is used in combat, but disciplines need a little extra rules to them. I currently have my NPC disciplines set to the nuke category and that almost works the way that I want with the only problem being that they will stack multiple discs at once which makes them way too overpowered. The idea is to make a new category just for discs that will do combat buffs, but only do 1 at a time and won't use another until the previous one has worn off.

I think the code I posted above for combat_buffs is probably very close to working for this. I just need to figure out why the new category wasn't being used when I set it for an NPC in their spell list. I imagine I am only missing something minor to get it to start using them. Then, the only other thing I would need is a way to make sure only 1 combat buff (disc) is being used at a time.

Of course since KLS added a new field for dispells and it is 512, then the new discipline field would have to use 1024. And if I added a combat_buff field as well for Yaulp and maybe others, it would have to be 2048.

If anyone has time to look over my code, I think these would make for some nice new features to help expand what NPCs can do without having to make quest scripts for every mob.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #3  
Old 09-02-2008, 10:03 PM
KLS
Administrator
 
Join Date: Sep 2006
Posts: 1,348
Default

Sir, get out of my head. I was seriously just thinking about expanding the npc cast system further with in combat buffs classification only like 2 days ago.
Reply With Quote
  #4  
Old 09-02-2008, 11:44 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

LMAO! SWEET! You keep saving me from work and trying to learn to program by examples from the source (which is no easy task).

So far, this is what I came up with, but it is missing the most important part (Changes are in RED):

MobAI.cpp
Code:
const int MobAISpellRange=100; // max range of buffs
const int SpellType_Nuke=1;
const int SpellType_Heal=2;
const int SpellType_Root=4;
const int SpellType_Buff=8;
const int SpellType_Escape=16;
const int SpellType_Pet=32;
const int SpellType_Lifetap=64;
const int SpellType_Snare=128;
const int SpellType_DOT=256;
const int SpellType_Dispel=512;
const int SpellType_Disc=1024;
const int SpellType_ComBuff=2048;

const int SpellTypes_Detrimental = SpellType_Nuke|SpellType_Root|SpellType_Lifetap|SpellType_Snare|SpellType_DOT|SpellType_Dispel|SpellType_Disc|SpellType_ComBuff;
const int SpellTypes_Beneficial = SpellType_Heal|SpellType_Buff|SpellType_Escape|SpellType_Pet;

This part is the main section and this is where the actual adjustments need to be made to tell the spells when to be used. This is not complete code in this section:
Code:
					case SpellType_Disc: {
						if (
							(spells[AIspells[i].spellid].targettype == ST_Target || tar == this)
							&& tar->DontBuffMeBefore() < Timer::GetCurrentTime()
							&& !tar->IsImmuneToSpell(AIspells[i].spellid, this)
							&& tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
							&& !(tar->IsPet() && tar->GetOwner()->IsClient() && this != tar)	//no buffing PC's pets, but they can buff themself
							) {
							AIDoSpellCast(i, tar, mana_cost, &tar->pDontBuffMeBefore);
							return true;
						}
						break;
					}


					case SpellType_ComBuff: {
						if (
							(spells[AIspells[i].spellid].targettype == ST_Target || tar == this)
							&& tar->DontBuffMeBefore() < Timer::GetCurrentTime()
							&& !tar->IsImmuneToSpell(AIspells[i].spellid, this)
							&& tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
							&& !(tar->IsPet() && tar->GetOwner()->IsClient() && this != tar)	//no buffing PC's pets, but they can buff themself
							) {
							AIDoSpellCast(i, tar, mana_cost, &tar->pDontBuffMeBefore);
							return true;
						}
						break;
					}

Code:
	if(		AIspells[i].type == SpellType_Nuke 
	   ||	AIspells[i].type == SpellType_Root
	   ||	AIspells[i].type == SpellType_Lifetap
	   ||	AIspells[i].type == SpellType_Snare
	   ||	AIspells[i].type == SpellType_DOT
	   ||	AIspells[i].type == SpellType_Dispel
	   ||	AIspells[i].type == SpellType_Disc
	   ||	AIspells[i].type == SpellType_ComBuff

Code:
bool NPC::AI_EngagedCastCheck() {
	if (AIautocastspell_timer->Check(false)) {
		_ZP(Mob_AI_Process_engaged_cast);
		AIautocastspell_timer->Disable();	//prevent the timer from going off AGAIN while we are casting.
		
		mlog(AI__SPELLS, "Engaged autocast check triggered. Trying to cast healing spells then maybe offensive spells.");
		
		// try casting a heal or gate
		if (!AICastSpell(this, 100, SpellType_Heal | SpellType_Escape)) {
			// try casting a heal on nearby
			if (!entity_list.AICheckCloseBeneficialSpells(this, 25, MobAISpellRange, SpellType_Heal)) {
				//nobody to heal, try some detrimental spells.
				if(!AICastSpell(target, 20, SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Disc | SpellType_ComBuff)) {
					//no spell to cast, try again soon.
					AIautocastspell_timer->Start(RandomTimer(500, 1000), false);
				}
			} //else, spell casting finishing will reset the timer.
		}
		return(true);
	}
	
	return(false);
}

bool NPC::AI_PursueCastCheck() {
	if (AIautocastspell_timer->Check(false)) {
		_ZP(Mob_AI_Process_pursue_cast);
		AIautocastspell_timer->Disable();	//prevent the timer from going off AGAIN while we are casting.
		
		mlog(AI__SPELLS, "Engaged (pursuing) autocast check triggered. Trying to cast offensive spells.");
		if(!AICastSpell(target, 90, SpellType_Root | SpellType_Nuke | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Disc | SpellType_ComBuff)) {
			//no spell cast, try again soon.
			AIautocastspell_timer->Start(RandomTimer(500, 2000), false);
		} //else, spell casting finishing will reset the timer.
		return(true);
	}
	return(false);
}
I imagine that combat buffs wouldn't be very hard to add. They would work like normal buffs, but only be cast during combat (mostly for Yaulp-Like spells with short duration and maybe some damage shields). The trickier one might be Disciplines, but I doubt it would be hard for KLS to do. Basically, Disciplines would need to cast the first disc and then not cast the second one until the buff duration was finished on the previous one. Or, they could all be treated like the same buff so that it won't cast another (cause it thinks of it as the same spell) until the buff timer fades. The only requirement for disciplines is that only one can be up at a time.

LOL, I am still laughing at KLS! I am just so glad to hear that I don't have to figure this out myself lol. Not that it would be a ton of work to do, cause I imagine it could be done pretty quick for someone with programming skill. But, mostly cause I am working on a new zone that will be more dynamic than any I have done so far and having more options for spells lists (especially disciplines) will really add a cool dynamic to the zone. My spell lists are done, but with them stacking discs, it makes them impossible to tune the encounters.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
Reply

Thread Tools
Display Modes

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 07:41 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 - 2025, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3