Go Back   EQEmulator Home > EQEmulator Forums > Archives > Archive::Development > Archive::Development

Archive::Development Archive area for Development's posts that were moved here after an inactivity period of 90 days.

 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
  #1  
Old 05-05-2004, 11:13 PM
bUsh
Sarnak
 
Join Date: Apr 2004
Location: Waukesha, WI
Posts: 93
Default The Green Leaf Changedump (Bug Fixes & Features - Huge)

The Green Leaf Changedump

Make sure you get my Monk & Beastlord Dual Wield Fix, Here:
http://www.eqemulator.net/forums/viewtopic.php?t=14676

This post includes all of the recent changes I have made to EQEmu 5.7-DR2 May 5th (Currently running these changes on The Green Leaf server!)
This includes a variety of bug fixes, as well as some new features, they will all be explained below.

But first, I'd like to REALLY thank Spike for volunteering over an hour of his time creating chars on live
and giving me their skills information. Thanks, Spike!


Ok, all the Dual Wield misspellings!
Here is each location to change:

mob.h - around line 472, change to:
Code:
bool	CanThisClassDualWield(void);
mob.cpp - around line 1349, change to:
Code:
bool Mob::CanThisClassDualWield(void)
client_process.cpp - around line 5342, change to:
Code:
if(auto_attack && !IsAIControlled() && CanThisClassDualWield() && target != 0 && attack_timer_dw->Check()&& !IsStunned() && !IsMezzed() && dead == 0) {
MobAI.cpp - around line 868, change to:
Code:
if (target && attack_timer_dw->Check() && CanThisClassDualWield())
zone\client.cpp - around line 2363 (Client::AutoPutLootInInventory) change to:
Code:
if
(
	i == SLOT_SECONDARY &&
	inst.IsWeapon() &&
	!CanThisClassDualWield()
)
skills.h - around line 47, change to:
Code:
#define DUAL_WIELD			22
skills.h - around line 125, change to:
Code:
#define DUAL_WIELD				22
mob.cpp - around like 1397, change to:
Code:
return (this->CastToClient()->GetSkill(DUAL_WIELD) != 0);	// No skill = no chance
mob.cpp - around line 1279, change to:
Code:
int8 tmp = this->CastToClient()->GetSkill(DUAL_WIELD);
client_process.cpp - around line 5356, change to:
Code:
float DualWieldProbability = (GetSkill(DUAL_WIELD) + GetLevel()) / 400.0f; // 78.0 max
and around line 5360, change to:
Code:
CheckIncreaseSkill(DUAL_WIELD);
and around line 5363, change to:
Code:
CheckIncreaseSkill(DUAL_WIELD);
Next, is a feature which disallows anyone without 100+ status to specify charges with #summonitem greater than the item's MaxCharges value.

command.cpp - around line 4858
Replace This:
Code:
else if (sep->IsNumber(2))
	c->SummonItem(itemid, atoi(sep->arg[2]));
else
	c->SummonItem(itemid);
With this:
Code:
else if ( sep->IsNumber(2) )
{
	if( (atoi(sep->arg[2]) > database.GetItem(itemid)->Common.MaxCharges) && (c->Admin() < 100) )
	{
		c->Message(13, "Error: This item cannot hold more than %i charge(s)", database.GetItem(itemid)->Common.MaxCharges );
	}
	else
	{
		c->SummonItem(itemid, atoi(sep->arg[2]));
	}
}
else
{
	c->SummonItem(itemid);
}
Next, is a cool feature which restricts the player from using expendable items while they are on the hate lists of any mobs in the zone.
(This does NOT affect items with unlimited charges)

client.h - around line 395, add:
Code:
inline sint32 AggroCount() { return entity_list.GetAggrodMobCount( this ); }
entity.h - around line 222, add (under ClearFeignAggro):
Code:
sint32 EntityList::GetAggrodMobCount(Mob* targ);
entity.cpp - around line 2266, add (under EntityList::ClearFeignAggro)
Code:
sint32 EntityList::GetAggrodMobCount(Mob* targ)
{
	LinkedListIterator<NPC*> iterator(npc_list);
	iterator.Reset();
	sint32 aggroCount = 0;
	while(iterator.MoreElements())
	{
		if ( iterator.GetData()->CastToNPC()->CheckAggro(targ) )
		{
			aggroCount++;
		}
		iterator.Advance();
	}
	
	return aggroCount;
}
Finally,

client_process.cpp - around line 2121
Replace this:
Code:
if ((item->Common.EffectType == 1) || (item->Common.EffectType == 3) || (item->Common.EffectType == 4) || (item->Common.EffectType == 5))
{
	CastSpell(item->Common.SpellId, castspell->target_id, castspell->slot, item->Common.CastTime, 0, 0, castspell->inventoryslot);
}
with this:
Code:
if ((item->Common.EffectType == 1) || (item->Common.EffectType == 3) || (item->Common.EffectType == 4) || (item->Common.EffectType == 5))
{
	if( (item->Common.MaxCharges != -1) && (AggroCount() > 0) )
	{
		Message(0, "This item cannot be used while engaging an enemy." );
		InterruptSpell(castspell->spell_id);
	}
	else
	{
		CastSpell(item->Common.SpellId, castspell->target_id, castspell->slot, item->Common.CastTime, 0, 0, castspell->inventoryslot);
	}
}
Next, is the missing skill-up check for Feign Death:

client_process.cpp - around line 1219
Replace This:
Code:
if (MakeRandomFloat(0, 300) > GetSkill(FEIGN_DEATH) && MakeRandomFloat(0, 4) == 1 && GetSkill(FEIGN_DEATH) < 200 && GetSkill(FEIGN_DEATH) < GetLevel()*5+5) {
	SetSkill(FEIGN_DEATH, GetSkill(FEIGN_DEATH) + 1);
}
break;
With this:
Code:
if (MakeRandomFloat(0, 300) > GetSkill(FEIGN_DEATH) && MakeRandomFloat(0, 4) == 1 && GetSkill(FEIGN_DEATH) < 200 && GetSkill(FEIGN_DEATH) < GetLevel()*5+5) {
	SetSkill(FEIGN_DEATH, GetSkill(FEIGN_DEATH) + 1);
}

CheckIncreaseSkill(FEIGN_DEATH);
break;
And, move CheckIncreaseSkill(TAUNT) from line 2502:
Code:
// no idea how taunt success is actually calculated
// TODO: chance for level 50+ mobs should be lower
CheckIncreaseSkill(TAUNT);
float tauntchance;
to line 2506 (a few lines above it)
Code:
}

CheckIncreaseSkill(TAUNT);

// Check to see if we're already at the top of the target's hate list
Next, fixes for CanThisClassDualWield, IsWarriorClass, CanThisClassParry, CanThisClassDodge, and CanThisClassRiposte.
Pasting full functions, just replace what you've got. (breaks and restructuring have been done, as well as a couple monk fixes)

mob.cpp - starting around line 1349, ending before GetClassLevelFactor
Replace corresponding functions with these:
Code:
bool Mob::CanThisClassDualWield(void) //Dual wield not Duel, busy someone else fix it
{
	// All npcs over level 13 can dual wield
	if (this->IsNPC() && (this->GetLevel() >= 13))
		return true;
	
	// Kaiyodo - Check the classes that can DW, and make sure we're not using a 2 hander
	switch(GetClass()) // Lets make sure they are the right level! -image
	{
	case WARRIOR:
	case ROGUE:
		{
			if(GetLevel() < 13)
				return false;
			break;
		}
	case BARD:
	case RANGER:
	case BEASTLORD:
		{
			if(GetLevel() < 17)
				return false;
			break;
		}
	case MONK:
		{
			break;
		}
	default:
		{
			return false;
		}
	}
	
	if (IsClient()) {
		const ItemInst* inst = CastToClient()->GetInv().GetItem(SLOT_PRIMARY);
		// 2HS, 2HB or 2HP
		if (inst && inst->IsType(ItemTypeCommon)) {
			const Item_Struct* item = inst->GetItem();
			if ((item->Common.Skill == 0x01) || (item->Common.Skill == 0x23) || (item->Common.Skill == 0x04))
				return false;
		}
		
		return (this->CastToClient()->GetSkill(DUAL_WIELD) != 0);	// No skill = no chance
	}
	else
		return false;
}

bool Mob::CanThisClassDoubleAttack(void)
{
    // All npcs over level 26 can double attack
    if (this->IsNPC() && this->GetLevel() >= 26)
        return true;
	// Kaiyodo - Check the classes that can DA
	switch(GetClass()) // Lets make sure they are the right level! -image
	{
	case WARRIOR:
	case MONK:
		{
			if(GetLevel() < 15)
				return false;
			break;
		}
	case ROGUE:
		{
			if(GetLevel() < 16)
				return false;
			break;
		}
	case RANGER:
	case PALADIN:
	case SHADOWKNIGHT:
		{
			if(GetLevel() < 20)
				return false;
			break;
		}
	default:
		{
			return false;
		}
	}

	if (this->IsClient())
		return(this->CastToClient()->GetSkill(DOUBLE_ATTACK) != 0);	// No skill = no chance
	else
		return false;
}

bool Mob::IsWarriorClass(void)
{
	switch(GetClass())
	{
	case WARRIOR:
	case WARRIORGM:
	case ROGUE:
	case ROGUEGM:
	case MONK:
	case MONKGM:
	case PALADIN:
	case PALADINGM:
	case SHADOWKNIGHT:
	case SHADOWKNIGHTGM:
	case RANGER:
	case RANGERGM:
	case BEASTLORD:
	case BEASTLORDGM:
	case BARD:
	case BARDGM:
		{
			return true;
		}
	default:
		{
			return false;
		}
	}

}

bool Mob::CanThisClassParry(void)
{
	// Trumpcard
	switch(GetClass()) // Lets make sure they are the right level! -image
	{
	case WARRIOR:
		{
		if(GetLevel() < 10)
			return false;
		break;
		}
	case ROGUE:
		{
		if(GetLevel() < 12)
			return false;
		break;
		}
	case BARD:
		{
		if(GetLevel() < 53)
			return false;
		break;
		}
	case RANGER:
		{
		if(GetLevel() < 18)
			return false;
		break;
		}
	case SHADOWKNIGHT:
	case PALADIN:
		{
		if(GetLevel() < 17)
			return false;
		break;
		}
	default:
		{
			return false;
		}
	}

	if (this->IsClient())
		return(this->CastToClient()->GetSkill(PARRY) != 0);	// No skill = no chance
	else
		return false;
}

bool Mob::CanThisClassDodge(void)
{
	// Trumpcard
	switch(GetClass()) // Lets make sure they are the right level! -image
	{
	case WARRIOR:
		{
			if(GetLevel() < 6)
				return false;
			break;
		}
	case MONK:
		{
			break;
		}
	case ROGUE:
		{
			if(GetLevel() < 4)
				return false;
			break;
		}
	case RANGER:
		{
			if(GetLevel() < 8)
				return false;
			break;
		}
	case BARD:
	case BEASTLORD:
	case SHADOWKNIGHT:
	case PALADIN:
		{
			if(GetLevel() < 10)
				return false;
			break;
		}
	case CLERIC:
	case SHAMAN:
	case DRUID:
		{
			if( GetLevel() < 15 )
				return false;
			break;
		}
	case NECROMANCER:
	case ENCHANTER:
	case WIZARD:
	case MAGICIAN:
		{
			if( GetLevel() < 22 )
				return false;
			break;
		}
	default:
		{
			return false;
		}
	}
	
	if (this->IsClient())
		return(this->CastToClient()->GetSkill(DODGE) != 0);	// No skill = no chance
	else
		return false;
}

bool Mob::CanThisClassRiposte(void) //Could just check if they have the skill?
{
	// Trumpcard
	switch(GetClass()) // Lets make sure they are the right level! -image
	{
	case WARRIOR:
		{
			if(GetLevel() < 25)
				return false;
			break;
		}
	case ROGUE:
	case RANGER:
	case SHADOWKNIGHT:
	case PALADIN:
		{
			if(GetLevel() < 30)
				return false;
			break;
		}
	case MONK:
		{
			if(GetLevel() < 35)
				return false;
		}
	case BEASTLORD:
		{
			if(GetLevel() < 40)
				return false;
		}
	case BARD:
		{
			if(GetLevel() < 58)
				return false;
		}
	default:
		{
			return false;
		}
	}
	
	if (this->IsClient())
		return(this->CastToClient()->GetSkill(RIPOSTE) != 0);	// No skill = no chance
	else
		return false;
}
With the previous fixes, we can now disable the ability for any class to Double Attack if they have the skill.

client_process.cpp - around line 5312
Replace this:
Code:
// Kaiyodo - support for double attack. Chance based on formula from Monkly business
if( GetSkill(DOUBLE_ATTACK) ) {
	float DoubleAttackProbability = (GetSkill(DOUBLE_ATTACK) + GetLevel()) / 500.0f; // 62.4 max
With this:
Code:
// Kaiyodo - support for double attack. Chance based on formula from Monkly business
if( CanThisClassDoubleAttack() ) {
	float DoubleAttackProbability = (GetSkill(DOUBLE_ATTACK) + GetLevel()) / 500.0f; // 62.4 max
Next, a few lines down in client_process.cpp, we add the same check for Double Attack on the Offhand
Just to be safe!

client_process.cpp - around line 5364
Replace this:
Code:
if (random < DualWieldProbability) { // Max 78% of DW
	Attack(target, 14);	// Single attack with offhand
	CheckIncreaseSkill(DUEL_WIELD);
	float DoubleAttackProbability = (GetSkill(DOUBLE_ATTACK) + GetLevel()) / 500.0f; // 62.4 max
	
	// Check for double attack with off hand assuming maxed DA Skill
	random = MakeRandomFloat(0, 1);
	if(random <= DoubleAttackProbability)	// Max 62.4% chance of DW/DA
		if(target && target->GetHP() > -10)
			Attack(target, 14);
}
With this:
Code:
if (random < DualWieldProbability) { // Max 78% of DW
	Attack(target, 14);	// Single attack with offhand
	CheckIncreaseSkill(DUAL_WIELD);
	
	if( CanThisClassDoubleAttack() )
	{
		float DoubleAttackProbability = (GetSkill(DOUBLE_ATTACK) + GetLevel()) / 500.0f; // 62.4 max
		
		// Check for double attack with off hand assuming maxed DA Skill
		random = MakeRandomFloat(0, 1);
		if(random <= DoubleAttackProbability)	// Max 62.4% chance of DW/DA
			if(target && target->GetHP() > -10)
				Attack(target, 14);
	}
}
Directly under the above block, I added the following, which gives the player a chance to increase in Dual Wield
without actually having to successfully DW. This is because at very low skill levels, DW was going up too slowly.
Once the DualWieldProbability reaches 0.1 or higher, this extra chance to skill up is skipped:

client_process.cpp - directly below the block above:
Code:
else if( DualWieldProbability < 0.1f )
{
	CheckIncreaseSkill(DUAL_WIELD); // bUsh - Speed Up skill increase at low skill levels
}
If you move up to around line 5319 in client_process.cpp
Replace this, which will increase skillups in Double Attack as well:
Code:
if( CanThisClassDoubleAttack() ) {
	float DoubleAttackProbability = (GetSkill(DOUBLE_ATTACK) + GetLevel()) / 500.0f; // 62.4 max
	// Check for double attack with main hand assuming maxed DA Skill (MS)
	float random = MakeRandomFloat(0, 1);
	if (random > 0.9)
		CheckIncreaseSkill(DOUBLE_ATTACK);
	if(random < DoubleAttackProbability)		// Max 62.4 % chance of DA
		if(target && target->GetHP() > -10){
			Attack(target, 13);
			CheckIncreaseSkill(DOUBLE_ATTACK);
		}
}
With:
Code:
if( CanThisClassDoubleAttack() ) {
	float DoubleAttackProbability = (GetSkill(DOUBLE_ATTACK) + GetLevel()) / 500.0f; // 62.4 max
	// Check for double attack with main hand assuming maxed DA Skill (MS)
	float random = MakeRandomFloat(0, 1);
	if (random > 0.9)
		CheckIncreaseSkill(DOUBLE_ATTACK);
	if(random < DoubleAttackProbability)		// Max 62.4 % chance of DA
	{
		if(target && target->GetHP() > -10){
			Attack(target, 13);
			CheckIncreaseSkill(DOUBLE_ATTACK);
		}
	}
	else if( DoubleAttackProbability < 0.1f )
	{
		CheckIncreaseSkill(DOUBLE_ATTACK); // bUsh - Speed Up skill increase at low skill levels
	}
}
(The reason for this was when looking at the random numbers generated, at low DW or DA Probability levels
it's EXTREMELY rare for the random number to drop below the probability, which gives you a chance to
skill up.)

This is my most important update!
I have implemented Racial Languages and Skills at Character Creation.

This is a LOT of updates, so bear with me here:

First, you need to move the file skills.h into the common directory.
Next, update these following lines to fix the new location:

zone\attack.cpp - line 32
zone\client.cpp - line 53
zone\client_process.cpp - line 55
zone\mob.cpp - line 25
zone\parser.cpp - line 19
zone\spells.cpp - line 82
zone\mob.h - line 47
Code:
#include "../common/skills.h"
world\client.cpp - line 36 ADD
Code:
#include "../common/languages.h"
#include "../common/skills.h"
Now add this file to the common directory:

common\languages.h
Code:
/*  EQEMu:  Everquest Server Emulator
    Copyright (C) 2001-2002  EQEMu Development Team (http://eqemu.org)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; version 2 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY except by those people which sell it, which
	are required to give you total support for your newly bought product;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR
	A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifndef LANGUAGES_H
#define LANGUAGES_H
#include "../common/types.h"

#define LANG_COMMON_TONGUE   0
#define LANG_BARBARIAN       1
#define LANG_ERUDIAN         2
#define LANG_ELVISH          3
#define LANG_DARK_ELVISH     4
#define LANG_DWARVISH        5
#define LANG_TROLL           6
#define LANG_OGRE            7
#define LANG_GNOMISH         8
#define LANG_HALFLING        9
#define LANG_THIEVES_CANT   10
#define LANG_OLD_ERUDIAN    11
#define LANG_ELDER_ELVISH   12
#define LANG_FROGLOK        13
#define LANG_GOBLIN         14
#define LANG_GNOLL          15
#define LANG_COMBINE_TONGUE 16
#define LANG_ELDER_TEIRDAL  17
#define LANG_LIZARDMAN      18
#define LANG_ORCISH         19
#define LANG_FAERIE         20
#define LANG_DRAGON         21
#define LANG_ELDER_DRAGON   22
#define LANG_DARK_SPEECH    23
#define LANG_VAH_SHIR       24
#define LANG_UNKNOWN1       25
#define LANG_UNKNOWN2       26

#endif
Then, open world\client.h, around line 67:
Code:
bool OPCharCreate(CharCreate_Struct *cc);
Add this under:
Code:
void SetClassStartingSkills( PlayerProfile_Struct *pp );
void SetRaceStartingSkills( PlayerProfile_Struct *pp );
void SetRacialLanguages( PlayerProfile_Struct *pp );
Now, open world\client.cpp, around line 964, change:
Code:
// FIXME: racial languages, FV roleplay, database goodness...
pp.languages[0] = 100;
to:
Code:
// FIXME: racial languages, FV roleplay, database goodness...
SetRacialLanguages( &pp ); // bUsh

SetRaceStartingSkills( &pp ); // bUsh
SetClassStartingSkills( &pp ); // bUsh
Scroll down to the bottom of world\client.cpp, and add all this:
Code:
void Client::SetClassStartingSkills( PlayerProfile_Struct *pp )
{
	switch( pp->class_ )
	{
	case BARD:
		{
			pp->skills[_1H_SLASHING + 1] = 5;
			pp->skills[SINGING + 1] = 5;
			break;
		}
	case BEASTLORD:
		{
			pp->skills[HAND_TO_HAND + 1] = 5;
			break;
		}
	case BERSERKER: // A Guess
		{
			pp->skills[_2H_SLASHING + 1] = 5;
			break;
		}
	case CLERIC:
		{
			pp->skills[_1H_BLUNT + 1] = 5;
			break;
		}
	case DRUID:
		{
			pp->skills[_1H_BLUNT + 1] = 5;
			break;
		}
	case ENCHANTER:
		{
			pp->skills[PIERCING + 1] = 5;
			break;
		}
	case MAGICIAN:
		{
			pp->skills[PIERCING + 1] = 5;
			break;
		}
	case MONK:
		{
			pp->skills[DODGE + 1] = 5;
			pp->skills[DUAL_WIELD + 1] = 5;
			pp->skills[HAND_TO_HAND + 1] = 5;
			break;
		}
	case NECROMANCER:
		{
			pp->skills[PIERCING + 1] = 5;
			break;
		}
	case PALADIN:
		{
			pp->skills[_1H_SLASHING + 1] = 5;
			break;
		}
	case RANGER:
		{
			pp->skills[_1H_SLASHING + 1] = 5;
			break;
		}
	case ROGUE:
		{
			pp->skills[PIERCING + 1] = 5;
			pp->languages[LANG_THIEVES_CANT] = 100; // Thieves Cant
			break;
		}
	case SHADOWKNIGHT:
		{
			pp->skills[_1H_SLASHING + 1] = 5;
			break;
		}
	case SHAMAN:
		{
			pp->skills[_1H_BLUNT + 1] = 5;
			break;
		}
	case WARRIOR:
		{
			pp->skills[_1H_SLASHING + 1] = 5;
			break;
		}
	case WIZARD:
		{
			pp->skills[PIERCING + 1] = 5;
			break;
		}
	}
}

void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp )
{
	switch( pp->race )
	{
	case BARBARIAN:
	case DWARF:
	case ERUDITE:
	case HALF_ELF:
	case HIGH_ELF:
	case HUMAN:
	case OGRE:
	case TROLL:
		{
			// No Race Specific Skills
			break;
		}
	case DARK_ELF:
		{
			pp->skills[HIDE + 1] = 50;
			break;
		}
	case FROGLOK:
		{
			pp->skills[SWIMMING + 1] = 125;
			break;
		}
	case GNOME:
		{
			pp->skills[TINKERING + 1] = 50;
			break;
		}
	case HALFLING:
		{
			pp->skills[HIDE + 1] = 50;
			pp->skills[SNEAK + 1] = 50;
			break;
		}
	case IKSAR:
		{
			pp->skills[FORAGE + 1] = 50;
			pp->skills[SWIMMING + 1] = 100;
			break;
		}
	case WOOD_ELF:
		{
			pp->skills[FORAGE + 1] = 50;
			pp->skills[HIDE + 1] = 50;
			break;
		}
	case VAHSHIR:
		{
			pp->skills[SAFE_FALL + 1] = 50;
			pp->skills[SNEAK + 1] = 50;
			break;
		}
	}
}

void Client::SetRacialLanguages( PlayerProfile_Struct *pp )
{
	switch( pp->race )
	{
	case BARBARIAN:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_BARBARIAN] = 100;
			break;
		}
	case DARK_ELF:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_DARK_ELVISH] = 100;
			pp->languages[LANG_DARK_SPEECH] = 100;
			pp->languages[LANG_ELDER_ELVISH] = 100;
			pp->languages[LANG_ELVISH] = 25;
			break;
		}
	case DWARF:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_DWARVISH] = 100;
			pp->languages[LANG_GNOMISH] = 25;
			break;
		}
	case ERUDITE:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_ERUDIAN] = 100;
			break;
		}
	case FROGLOK:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_FROGLOK] = 100;
			pp->languages[LANG_TROLL] = 25;
			break;
		}
	case GNOME:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_DWARVISH] = 25;
			pp->languages[LANG_GNOMISH] = 100;
			break;
		}
	case HALF_ELF:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_ELVISH] = 100;
			break;
		}
	case HALFLING:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_HALFLING] = 100;
			break;
		}
	case HIGH_ELF:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_DARK_ELVISH] = 25;
			pp->languages[LANG_ELDER_ELVISH] = 25;
			pp->languages[LANG_ELVISH] = 100;
			break;
		}
	case HUMAN:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			break;
		}
	case IKSAR:
		{
			pp->languages[LANG_COMMON_TONGUE] = 95;
			pp->languages[LANG_DARK_SPEECH] = 100;
			pp->languages[LANG_LIZARDMAN] = 100;
			break;
		}
	case OGRE:
		{
			pp->languages[LANG_COMMON_TONGUE] = 95;
			pp->languages[LANG_DARK_SPEECH] = 100;
			pp->languages[LANG_OGRE] = 100;
			break;
		}
	case TROLL:
		{
			pp->languages[LANG_COMMON_TONGUE] = 95;
			pp->languages[LANG_DARK_SPEECH] = 100;
			pp->languages[LANG_TROLL] = 100;
			break;
		}
	case WOOD_ELF:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_ELVISH] = 100;
			break;
		}
	case VAHSHIR:
		{
			pp->languages[LANG_COMMON_TONGUE] = 100;
			pp->languages[LANG_COMBINE_TONGUE] = 100;
			pp->languages[LANG_ERUDIAN] = 25;
			pp->languages[LANG_VAH_SHIR] = 100;
			break;
		}
	}
}
Next, Open zone\command.h, line 127, add after void command_castspell:
Code:
void command_setlanguage(Client *c, const Seperator *sep);
Now, open zone\command.cpp, line 240, right above command_add("setskill"...), add:
Code:
command_add("setlanguage","[language ID] [value] - Set your target's language skillnum to value",50,command_setlanguage) ||
Scroll down to around line 2300 in zone\command.cpp, add this func
above void command_setskill:
Code:
void command_setlanguage(Client *c, const Seperator *sep)
{
	if( c->GetTarget() == 0 )
	{
		c->Message(0, "Error: #setlanguage: No target.");
	}
	else if( !c->GetTarget()->IsClient() )
	{
		c->Message(0, "Error: Target must be a player.");
	}
	else if ( strcasecmp( sep->arg[1], "list" ) == 0 )
	{
		c->Message(0, "Languages:");
		c->Message(0, "     (0) Common Tongue");
		c->Message(0, "     (1) Barbarian");
		c->Message(0, "     (2) Erudian");
		c->Message(0, "     (3) Elvish");
		c->Message(0, "     (4) Dark Elvish");
		c->Message(0, "     (5) Dwarvish");
		c->Message(0, "     (6) Troll");
		c->Message(0, "     (7) Ogre");
		c->Message(0, "     (8) Gnomish");
		c->Message(0, "     (9) Halfling");
		c->Message(0, "    (10) Thieves Cant");
		c->Message(0, "    (11) Old Erudian");
		c->Message(0, "    (12) Elder Elvish");
		c->Message(0, "    (13) Froglok");
		c->Message(0, "    (14) Goblin");
		c->Message(0, "    (15) Gnoll");
		c->Message(0, "    (16) Combine Tongue"); 
		c->Message(0, "    (17) Elder Teir`Dal");
		c->Message(0, "    (18) Lizardman");
		c->Message(0, "    (19) Orcish");
		c->Message(0, "    (20) Faerie");
		c->Message(0, "    (21) Dragon");
		c->Message(0, "    (22) Elder Dragon");
		c->Message(0, "    (23) Dark Speech");
		c->Message(0, "    (24) Vah Shir");
		c->Message(0, "    (25) Unknown1");
		c->Message(0, "    (26) Unknown2");
	}
	else if (	
						!sep->IsNumber(1) || atoi(sep->arg[1]) < 0 || atoi(sep->arg[1]) > 26 ||
						!sep->IsNumber(2) || atoi(sep->arg[2]) < 0 || atoi(sep->arg[2]) > 100
					)
	{
		c->Message(0, "Usage: #setlanguage [language ID] [value] (0-26, 0-100)");
		c->Message(0, "Try #setlanguage list for a list of language IDs");
	}
	else
	{
		LogFile->write(EQEMuLog::Normal,"Set language request from %s, target:%s lang_id:%i value:%i", c->GetName(), c->GetTarget()->GetName(), atoi(sep->arg[1]), atoi(sep->arg[2]) );
		int8 langid = (int8)atoi(sep->arg[1]);
		int8 value = (int8)atoi(sep->arg[2]);
		c->GetTarget()->CastToClient()->SetLanguage( langid, value );
	}
}
Now, if you use the PERL zone.exe's, open embparser.cpp, line 421
add these two lines:
Code:
"sub setlanguage{push(@cmd_queue,{func=>'setlanguage',args=>join(',',@_)});}" // bUsh
"sub setskill{push(@cmd_queue,{func=>'setskill',args=>join(',',@_)});}" // bUsh
For QST:
parser.cpp - around line 47, add to end of 'string cmds' line:
Code:
setskill 2|setlanguage 2|");
parser.cpp - around line 982, add:
Code:
else if (!strcmp(strlwr(command), "setlanguage")) { // bUsh
	if (mob && mob->IsClient()) mob->CastToClient()->SetLanguage(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(strlwr(command),"setskill")) { // bUsh
	if (mob && mob->IsClient()) mob->CastToClient()->SetSkill(atoi(arglist[0]), atoi(arglist[1]));
}
zone\client.cpp - around line 4273 (GetEquipmentColor, then end of file), add:
Code:
void Client::SetLanguage(int langid, int value)
{
	if (langid > 26)
		return;
	if( value <= 100 )
	{
		m_pp.languages[langid] = value;

		Message_StringID( 270, 449 );
	}
}
Finally, in zone\client.h, around line 396, add these two lines:
Code:
void    SetLanguage(int langid, int value); // bUsh
int     GetLanguage(int langid) { if (langid <= MAX_PP_LANGUAGE) { return m_pp.languages[langid]; } return 0; }
That's it! You're done!
All classes & races will now be created with the correct skills as well as languages!

Please let me know of any problems you have, or anything I missed. It is 6am and I've been coding all night, it's bound to happen!
__________________
~ b [ u ] s h

* ServerOP * The Green Leaf Server
Reply With Quote
 


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 12:01 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