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

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

Reply
 
Thread Tools Display Modes
  #16  
Old 05-12-2009, 04:57 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Yeah, I am not quite sure why they have it changing the values at all, but it seems to change them to 99 or 255 in some cases. As far as I can tell, we shouldn't be changing anything and just save the actual value and call the actual value. The conversions it is doing is almost certainly the cause of baldness and why faces have had so many issues in the past.

I know KLS did quite a bit of work on facial features in the past and I am wondering if she has any input on why those values are changed like that before I start making changes so that it uses the actual value instead of all of this converting.

Oh yeah, Drakkin NPCs look much cooler now that they aren't all exactly the same.

Another thing I wanted to mention is that a while back, I got the illusion struct all identified other than the Drakkin specific stuff. It would be nice if we could get facechange and other facial features added into the illusion function since they currently are not. I think the problem is that Titanium doesn't have the illusion struct filled out fully, so no one bothered to finish the function for illusion to add in the other features. It would also be very cool to have armor stuff (texture and tint) in the illusion function. Then, when someone clicks off an illusion, they would actually look exactly like they did before the illusion was cast instead of just returning to the same race and armor texture. I am pretty sure everything is in the illusion struct and we just need to find the armor and Drakkin stuff to completely finalize it. It wouldn't be hard to finalize the struct, but the code to handle all of it might take a bit of work to do. It would be awesome to expand the #fixmob functionality to work with faces, hairstyle, haircolor, eyecolor, beard, beardcolor, armor tint, and the new Drakkin features. Then, you could really fine tune an NPC in realtime before creating it in the database. Otherwise, it means a database change and a repop to see how it looks. Much quicker and easier to just have hotkeys and spam through the different looks until you find one you like.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 05-13-2009 at 01:15 AM..
Reply With Quote
  #17  
Old 05-12-2009, 08:01 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Here are at least a couple places where we can try removing the 99 change for features set to 0 and see if that corrects the issues with bald players and features not showing up correctly once and for all:


zone/client_packet.cpp
Code:
void Client::Handle_OP_FaceChange(const EQApplicationPacket *app)
{
	if (app->size != sizeof(FaceChange_Struct)) {
		LogFile->write(EQEMuLog::Error, "Invalid size for OP_FaceChange: Expected: %i, Got: %i",
			sizeof(FaceChange_Struct), app->size);
		return;
	}

	// Notify other clients in zone
	entity_list.QueueClients(this, app, false);

	FaceChange_Struct* fc = (FaceChange_Struct*)app->pBuffer;
	m_pp.haircolor	= fc->haircolor;
	m_pp.beardcolor	= fc->beardcolor;
	m_pp.eyecolor1	= fc->eyecolor1;
	m_pp.eyecolor2	= fc->eyecolor2;
	m_pp.hairstyle	= fc->hairstyle;
	m_pp.face		= fc->face;
// vesuvias - appearence fix
	m_pp.beard		= fc->beard;

if (fc->face == 0)       {m_pp.face = 99;}
	if (fc->eyecolor1 == 0)  {m_pp.eyecolor1 = 99;}
	if (fc->eyecolor2 == 0)  {m_pp.eyecolor2 = 99;}
	if (fc->hairstyle == 0)  {m_pp.hairstyle = 99;}
	if (fc->haircolor == 0)  {m_pp.haircolor = 99;}
	if (fc->beard == 0)      {m_pp.beard = 99;}
	if (fc->beardcolor == 0) {m_pp.beardcolor = 99;}

	Save();
	Message_StringID(13,FACE_ACCEPTED);
	//Message(13, "Facial features updated.");
	return;
}
world/client.cpp
Code:
bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
{
	PlayerProfile_Struct pp; 
	ExtendedProfile_Struct ext;
	Inventory inv;
	time_t bday = time(NULL);
	char startzone[50]={0};
	uint32 i;
	struct in_addr	in;

			
	int stats_sum = cc->STR + cc->STA + cc->AGI + cc->DEX + 
		cc->WIS + cc->INT + cc->CHA;

	in.s_addr = GetIP();
	clog(WORLD__CLIENT,"Character creation request from %s LS#%d (%s:%d) : ", GetCLE()->LSName(), GetCLE()->LSID(), inet_ntoa(in), GetPort());
	clog(WORLD__CLIENT,"Name: %s", name);
	clog(WORLD__CLIENT,"Race: %d  Class: %d  Gender: %d  Deity: %d  Start zone: %d",
		cc->race, cc->class_, cc->gender, cc->deity, cc->start_zone);
	clog(WORLD__CLIENT,"STR  STA  AGI  DEX  WIS  INT  CHA    Total");
	clog(WORLD__CLIENT,"%3d  %3d  %3d  %3d  %3d  %3d  %3d     %3d",
		cc->STR, cc->STA, cc->AGI, cc->DEX, cc->WIS, cc->INT, cc->CHA, 
		stats_sum);
	clog(WORLD__CLIENT,"Face: %d  Eye colors: %d %d", cc->face, cc->eyecolor1, cc->eyecolor2);
	clog(WORLD__CLIENT,"Hairstyle: %d  Haircolor: %d", cc->hairstyle, cc->haircolor);
	clog(WORLD__CLIENT,"Beard: %d  Beardcolor: %d", cc->beard, cc->beardcolor);

	// validate the char creation struct
	if(!CheckCharCreateInfo(cc))
	{
		clog(WORLD__CLIENT_ERR,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
		return false;
	}

	// Convert incoming cc_s to the new PlayerProfile_Struct
	memset(&pp, 0, sizeof(PlayerProfile_Struct));	// start building the profile
	
	InitExtendedProfile(&ext);
	
	strncpy(pp.name, name, 63);
	// clean the capitalization of the name
#if 0	// on second thought, don't - this will just make the creation fail
// because the name won't match what was already reserved earlier
	for (i = 0; pp.name[i] && i < 63; i++)
	{
		if(!isalpha(pp.name[i]))
			return false;
		pp.name[i] = tolower(pp.name[i]);
	}
	pp.name[0] = toupper(pp.name[0]);	
#endif

	pp.race				= cc->race;
	pp.class_			= cc->class_;
	pp.gender			= cc->gender;
	pp.deity			= cc->deity;
	pp.STR				= cc->STR;
	pp.STA				= cc->STA;
	pp.AGI				= cc->AGI;
	pp.DEX				= cc->DEX;
	pp.WIS				= cc->WIS;
	pp.INT				= cc->INT;
	pp.CHA				= cc->CHA;
	pp.face				= cc->face;
	pp.eyecolor1	= cc->eyecolor1;
	pp.eyecolor2	= cc->eyecolor2;
	pp.hairstyle	= cc->hairstyle;
	pp.haircolor	= cc->haircolor;
	pp.beard		 	= cc->beard;
	pp.beardcolor	= cc->beardcolor;

if (cc->face == 0)       {pp.face = 99;}
	if (cc->eyecolor1 == 0)  {pp.eyecolor1 = 99;}
	if (cc->eyecolor2 == 0)  {pp.eyecolor2 = 99;}
	if (cc->hairstyle == 0)  {pp.hairstyle = 99;}
	if (cc->haircolor == 0)  {pp.haircolor = 99;}
	if (cc->beard == 0)      {pp.beard = 99;}
	if (cc->beardcolor == 0) {pp.beardcolor = 99;}

	pp.birthday		= bday;
	pp.lastlogin	= bday;
	pp.level			= 1;
	pp.points			= 5;
	pp.cur_hp			= 1000; // 1k hp during dev only
	//what was the point of this? zone dosent handle this:
	//pp.expAA			= 0xFFFFFFFF;

	pp.hunger_level = 6000;
	pp.thirst_level = 6000;


	// FIXME: FV roleplay, database goodness...

	// Racial Languages
	SetRacialLanguages( &pp ); // bUsh
	SetRaceStartingSkills( &pp ); // bUsh
	SetClassStartingSkills( &pp ); // bUsh
	pp.skills[SENSE_HEADING] = 200;
	// Some one fucking fix this to use a field name. -Doodman
	//pp.unknown3596[28] = 15; // @bp: This is to enable disc usage
//	strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
			

	for(i = 0; i < MAX_PP_SPELLBOOK; i++)
		pp.spell_book[i] = 0xFFFFFFFF;

	for(i = 0; i < MAX_PP_MEMSPELL; i++)
		pp.mem_spells[i] = 0xFFFFFFFF;

	for(i = 0; i < BUFF_COUNT; i++)
		pp.buffs[i].spellid = 0xFFFF;

	
	//was memset(pp.unknown3704, 0xffffffff, 8);
	//but I dont think thats what you really wanted to do...
	//memset is byte based
	
	//If server is PVP by default, make all character set to it.
	pp.pvp = database.GetServerType() == 1 ? 1 : 0;			
		
	// if there's a startzone variable put them in there
	if(database.GetVariable("startzone", startzone, 50))
	{
		clog(WORLD__CLIENT,"Found 'startzone' variable setting: %s", startzone);
		pp.zone_id = database.GetZoneID(startzone);
		if(pp.zone_id)
			database.GetSafePoints(pp.zone_id, &pp.x, &pp.y, &pp.z);
		else
			clog(WORLD__CLIENT_ERR,"Error getting zone id for '%s'", startzone);
	}
	else	// otherwise use normal starting zone logic
	{
		if(!SoFClient)
			database.GetStartZone(&pp, cc);
		else
			database.GetStartZoneSoF(&pp, cc);
	}

	if(!pp.zone_id)
	{
		pp.zone_id = 1;		// qeynos
		pp.x = pp.y = pp.z = -1;
	}

	if(!pp.binds[0].zoneId)
	{
		pp.binds[0].zoneId = pp.zone_id;
		pp.binds[0].x = pp.x;
		pp.binds[0].y = pp.y;
		pp.binds[0].z = pp.z;
		pp.binds[0].heading = pp.heading;
 	}

		
	clog(WORLD__CLIENT,"Current location: %s  %0.2f, %0.2f, %0.2f",
		database.GetZoneName(pp.zone_id), pp.x, pp.y, pp.z);
	clog(WORLD__CLIENT,"Bind location: %s  %0.2f, %0.2f, %0.2f",
		database.GetZoneName(pp.binds[0].zoneId), pp.binds[0].x, pp.binds[0].y, pp.binds[0].z);


	// Starting Items inventory
	database.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());
			
			
	// now we give the pp and the inv we made to StoreCharacter
	// to see if we can store it
	if (!database.StoreCharacter(GetAccountID(), &pp, &inv, &ext))
	{
		clog(WORLD__CLIENT_ERR,"Character creation failed: %s", pp.name);
		return false;
	}
	else
	{
		clog(WORLD__CLIENT,"Character creation successful: %s", pp.name);
		return true;
	}
}
worlddb.cpp
Code:
void WorldDatabase::GetCharSelectInfo(int32 account_id, CharacterSelect_Struct* cs) {
	char errbuf[MYSQL_ERRMSG_SIZE];
	char* query = 0;
	MYSQL_RES *result;
	MYSQL_ROW row;
	Inventory *inv;
	
	for (int i=0; i<10; i++) {
		strcpy(cs->name[i], "<none>");
		cs->zone[i] = 0;
		cs->level[i] = 0;
            cs->tutorial[i] = 0;
		cs->gohome[i] = 0;
	}
	
	int char_num = 0;
	unsigned long* lengths;
	
	// Populate character info
	if (RunQuery(query, MakeAnyLenString(&query, "SELECT name,profile,zonename,class,level FROM character_ WHERE account_id=%i order by name limit 10", account_id), errbuf, &result)) {
		safe_delete_array(query);
		while ((row = mysql_fetch_row(result))) {
			lengths = mysql_fetch_lengths(result);
			////////////
			////////////	This is the current one, the other are for converting
			////////////
			if ((lengths[1] == sizeof(PlayerProfile_Struct))) {
				strcpy(cs->name[char_num], row[0]);
				PlayerProfile_Struct* pp = (PlayerProfile_Struct*)row[1];
				uint8 clas = atoi(row[3]);
				uint8 lvl = atoi(row[4]);
				
				// Character information
				if(lvl == 0)
					cs->level[char_num]				= pp->level;	//no level in DB, trust PP
				else
					cs->level[char_num]				= lvl;
				if(clas == 0)
					cs->class_[char_num]			= pp->class_;	//no class in DB, trust PP
				else
					cs->class_[char_num]			= clas;
				cs->race[char_num]				= pp->race;
				cs->gender[char_num]			= pp->gender;
				cs->deity[char_num]				= pp->deity;
				cs->zone[char_num]				= GetZoneID(row[2]);
				cs->face[char_num]				= pp->face;
				cs->haircolor[char_num]		= pp->haircolor;
				cs->beardcolor[char_num]	= pp->beardcolor;
				cs->eyecolor2[char_num] 	= pp->eyecolor2;
				cs->eyecolor1[char_num] 	= pp->eyecolor1;
				cs->hair[char_num]				= pp->hairstyle;
				cs->beard[char_num]				= pp->beard;
if (pp->face == 99)       {cs->face[char_num] = 0;}
if (pp->eyecolor1 == 99)  {cs->eyecolor1[char_num] = 0;}
if (pp->eyecolor2 == 99)  {cs->eyecolor2[char_num] = 0;}
if (pp->hairstyle == 99)  {cs->hair[char_num] = 0;}
if (pp->haircolor == 99)  {cs->haircolor[char_num] = 0;}
if (pp->beard == 99)      {cs->beard[char_num] = 0;}
if (pp->beardcolor == 99) {cs->beardcolor[char_num] = 0;}
				
				if(RuleB(World, EnableTutorialButton) && (lvl <= RuleI(World, MaxLevelForTutorial)))
					cs->tutorial[char_num] = 1;

				if(RuleB(World, EnableReturnHomeButton)) {
					int now = time(NULL);
					if((now - pp->lastlogin) >= RuleI(World, MinOfflineTimeToReturnHome))
						cs->gohome[char_num] = 1;
				}

				// Character's equipped items
				// @merth: Haven't done bracer01/bracer02 yet.
				// Also: this needs a second look after items are a little more solid
				// NOTE: items don't have a color, players MAY have a tint, if the
				// use_tint part is set.  otherwise use the regular color
				inv = new Inventory;
				if(GetInventory(account_id, cs->name[char_num], inv))
				{
					for (uint8 material = 0; material <= 8; material++)
					{
						uint32 color;
						ItemInst *item = inv->GetItem(Inventory::CalcSlotFromMaterial(material));
						if(item == 0)
							continue;

						cs->equip[char_num][material] = item->GetItem()->Material;

						if(pp->item_tint[material].rgb.use_tint)	// they have a tint (LoY dye)
							color = pp->item_tint[material].color;
						else	// no tint, use regular item color
							color = item->GetItem()->Color;

						cs->cs_colors[char_num][material].color = color;

						// the weapons are kept elsewhere
						if ((material==MATERIAL_PRIMARY) || (material==MATERIAL_SECONDARY))
						{
							if(strlen(item->GetItem()->IDFile) > 2) {
								int32 idfile=atoi(&item->GetItem()->IDFile[2]);
								if (material==MATERIAL_PRIMARY)
									cs->primary[char_num]=idfile;
								else
									cs->secondary[char_num]=idfile;
							}
						}
					}
				}
				else
				{
					printf("Error loading inventory for %s\n", cs->name[char_num]);
				}
				safe_delete(inv);	
				if (++char_num > 10)
					break;
			}
			else
			{
				cout << "Got a bogus character (" << row[0] << ") Ignoring!!!" << endl;
				cout << "PP length ="<<lengths[1]<<" but PP should be "<<sizeof(PlayerProfile_Struct)<<endl;
				//DeleteCharacter(row[0]);
			}
		}
		mysql_free_result(result);
	}
	else
	{
		cerr << "Error in GetCharSelectInfo query '" << query << "' " << errbuf << endl;
		safe_delete_array(query);
		return;
	}
	
	return;
}
mob.cpp
Code:
void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
{
	int i;

	strcpy(ns->spawn.name, name);
	if(IsClient())
		strncpy(ns->spawn.lastName,lastname,sizeof(lastname));
	ns->spawn.heading	= FloatToEQ19(heading);
	ns->spawn.x			= FloatToEQ19(x_pos);//((sint32)x_pos)<<3;
	ns->spawn.y			= FloatToEQ19(y_pos);//((sint32)y_pos)<<3;
	ns->spawn.z			= FloatToEQ19(z_pos);//((sint32)z_pos)<<3;
	ns->spawn.spawnId	= GetID();
	ns->spawn.curHp	= (sint16)GetHPRatio();
	ns->spawn.max_hp	= 100;		//this field needs a better name
	ns->spawn.race		= race;
	ns->spawn.runspeed	= runspeed;
	ns->spawn.walkspeed	= runspeed * 0.5f;
	ns->spawn.class_	= class_;
	ns->spawn.gender	= gender;
	ns->spawn.level		= level;
	ns->spawn.deity		= deity;
	ns->spawn.animation	= 0;
	ns->spawn.findable	= findable?1:0;
// vesuvias - appearence fix
	ns->spawn.light		= light;


	ns->spawn.invis		= (invisible || hidden) ? 1 : 0;	// TODO: load this before spawning players
	ns->spawn.NPC		= IsClient() ? 0 : 1;
	ns->spawn.petOwnerId	= ownerid;

	ns->spawn.haircolor = haircolor ? haircolor : 0xFF;
	ns->spawn.beardcolor = beardcolor ? beardcolor : 0xFF;
	ns->spawn.eyecolor1 = eyecolor1 ? eyecolor1 : 0xFF;
	ns->spawn.eyecolor2 = eyecolor2 ? eyecolor2 : 0xFF;
	ns->spawn.hairstyle = hairstyle ? hairstyle : 0xFF;
	ns->spawn.face = luclinface;
	ns->spawn.beard = beard ? beard : 0xFF;
	ns->spawn.equip_chest2  = texture;

//	ns->spawn.invis2 = 0xff;//this used to be labeled beard.. if its not FF it will turn
								   //mob invis

	if(helmtexture && helmtexture != 0xFF)
	{
		//ns->spawn.equipment[MATERIAL_HEAD] = helmtexture;
		ns->spawn.helm=helmtexture;
	} else {
		//ns->spawn.equipment[MATERIAL_HEAD] = 0;
		ns->spawn.helm = 0;
	}
	
	ns->spawn.guildrank	= 0xFF;
	ns->spawn.size			= size;
	ns->spawn.bodytype = bodytype;
	// The 'flymode' settings have the following effect:
	// 0 - Mobs in water sink like a stone to the bottom
	// 1 - Same as #flymode 1
	// 2 - Same as #flymode 2
	// 3 - Mobs in water do not sink. A value of 3 in this field appears to be the default setting for all mobs
	//     (in water or not) according to 6.2 era packet collects.
	if(IsClient())
		ns->spawn.flymode = 0;
	else
		ns->spawn.flymode = 3;
	
	ns->spawn.lastName[0] = '\0';
	
	strncpy(ns->spawn.lastName, lastname, sizeof(lastname));

	for(i = 0; i < MAX_MATERIALS; i++)
	{
		ns->spawn.equipment[i] = GetEquipmentMaterial(i);
		ns->spawn.colors[i].color = GetEquipmentColor(i);
	}
	
	memset(ns->spawn.set_to_0xFF, 0xFF, sizeof(ns->spawn.set_to_0xFF));
	
}
It makes sense that NPCs load perfectly as they are set because they don't do these weird conversions. So, I think it is logical to conclude that the 99 and the 0xFF settings that are getting done are to blame for PCs not showing up properly. Seems to me like things were being overcomplicated when they should just save the number that is set and use that same number when loading the settings. The bald characters and the white hair issues should both be caused by the 99 and 0xFF settings, so removing that should correct them.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 05-13-2009 at 06:54 AM..
Reply With Quote
  #18  
Old 05-13-2009, 12:07 AM
Shendare
Dragon
 
Join Date: Apr 2009
Location: California
Posts: 814
Default

Changes needed to implement face changing in SoF:

Code:
// eq_packet_structs.h
struct FaceChange_Struct {
/*000*/	int8	haircolor;
/*001*/	int8	beardcolor;
/*002*/	int8	eyecolor1;
/*003*/	int8	eyecolor2;
/*004*/	int8	hairstyle;
/*005*/	int8	beard;
/*006*/	int8	face;
/*007*/ int8	unknown07;
/*008*/ int32	heritage;
/*012*/ int32	tattoo;
/*016*/ int32	details;
/*020*/ int32	unknown;
};
Code:
// client_packet.cpp - Client::Handle_OP_FaceChange()
void Client::Handle_OP_FaceChange(const EQApplicationPacket *app)
{
  // [snip] ...
	
	// FaceChange sends 0xFF as code for "Field Not Applicable For This Race"
	// Except Drakkin fields, which are always 0 for non-Drakkin.
	// Better to store 0 in DB than 0xFF in case race changes,
	//   because then field may become applicable again!
	m_pp.hair = (fc->hair == 0xFF) ? 0 : fc->hair;
	m_pp.haircolor = (fc->haircolor == 0xFF) ? 0 : fc->haircolor;
	m_pp.beard = (fc->beard == 0xFF) ? 0 : fc->beard;
	m_pp.beardcolor = (fc->beardcolor == 0xFF) ? 0 : fc->beard;

	switch (m_pp.race)
	{
		case BARBARIAN:
			m_pp.tattoo = (fc->face / 10);
			m_pp.face = (fc->face % 10);
			break;
		case ERUDITE:
			m_pp.hair = (fc->face / 10);
			m_pp.face = (fc->face % 10);
			break;
		case HIGHELF:
		case DARKELF:
		case HALFELF:
			m_pp.beard = (fc->face / 10);
			m_pp.face = (fc->face % 10);
			break;
		case 
	}
}
Code:
// SoF.cpp - ENCODE(OP_ZoneSpawns)
ENCODE(OP_ZoneSpawns)
{
  // [snip] ...
	
	eq->tattoo = emu->tattoo; // Assuming Tattoo field is added to DB for Draks & Barbs
	eq->details = emu->details; // Assuming Details field is added to DB for Draks
	eq->heritage = emu->heritage; // Assuming heritage field is added to DB for Draks
	eq->face = emu->face;

	// Now adjust Face field to account for features encoded into it by client for rendering
	switch (emu->race)
	{
	  case BARBARIAN:
			eq->face += (emu->tattoo * 10); // Tattoo will be ignored by client for Barbs, Tattoo maps to Face field.
			break;
		case ERUDITE:
			eq->face += (emu->hair * 10); // Hair will be ignored by client for Eruds, Hair maps to Face field
			break;
		case HIGHELF:
		case DARKELF:
		case HALFELF:
			eq->face += (emu->beard * 10); // Beard will be ignored by client for elves, Beard maps to Face field
			break;
	}

	// ... [snip]
}
Reply With Quote
  #19  
Old 05-13-2009, 04:27 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Identified the Drakkin portion of the Character Select Struct:

Code:
struct CharacterSelectEntry_Struct {
/*0000*/	uint8 level;				//
/*0001*/	uint8 haircolor;			//
/*0002*/	uint8 gender;				//
/*0003*/	char name[1];				//variable length, edi+0
/*0000*/	uint8 beard;				//
/*0000*/	uint8 hair;					//
/*0000*/	uint8 face;					//
/*0000*/	CharSelectEquip	equip[9];
/*0000*/	uint32 secondary;			//
/*0000*/	uint32 primary;				//
/*0000*/	uint8 u15;					// 0xff
/*0000*/	uint32 deity;				//
/*0000*/	uint16 zone;				//
/*0000*/	uint16 instance;
/*0000*/	uint8 gohome;				//
/*0000*/	uint8 u19;					// 0xff
/*0000*/	uint32 race;				//
/*0000*/	uint8 tutorial;				//
/*0000*/	uint8 class_;				//
/*0000*/	uint8 eyecolor1;			//
/*0000*/	uint8 beardcolor;			//
/*0000*/	uint8 eyecolor2;			//
/*0000*/	uint32 drakkin_heritage;	// Drakkin Heritage
/*0000*/	uint32 drakkin_tattoo;		// Drakkin Tattoo
/*0000*/	uint32 drakkin_details;		// Drakkin Details (Facial Spikes)
};
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #20  
Old 05-13-2009, 11:15 PM
Shendare
Dragon
 
Join Date: Apr 2009
Location: California
Posts: 814
Default

Sweeeeeet.

Just as a heads up, client_packet.cpp is still scrambling features that are set to 0. Commenting out these lines fixes the problem and allows all appearance settings set with the Face change button to stick between game sessions!

client_packet.cpp, lines 4684-4691
Code:
	/*
	if (fc->face == 0)       {m_pp.face = 99;}
	if (fc->eyecolor1 == 0)  {m_pp.eyecolor1 = 99;}
	if (fc->eyecolor2 == 0)  {m_pp.eyecolor2 = 99;}
	if (fc->hairstyle == 0)  {m_pp.hairstyle = 99;}
	if (fc->haircolor == 0)  {m_pp.haircolor = 99;}
	if (fc->beard == 0)      {m_pp.beard = 99;}
	if (fc->beardcolor == 0) {m_pp.beardcolor = 99;}
	*/
Drakkin features excluded from full functionality, of course, until we can get the fields added to the DB.
Reply With Quote
  #21  
Old 05-14-2009, 03:45 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Yeah, there are still a few places that do that conversion. I am trying to figure out a couple of things before I change anymore facial feature stuff on the SVN. As it is, the one change to stop them from setting to 0xFF that I put on is probably already causing feature issues again. I am not quite sure what the issue is atm, so holding off on more changes for now so that if a revert is required, it won't be hard to do it.

Between SoF and Titanium, it seems like features act a bit differently. I also noticed that Titanium does an encode on the spawn packet and it does that conversion from 99 back to 0 again.

I may be wrong, but from looking at the code, it seems like the whole reason to do the 99 and 0xFF conversion stuff was because in the past it may have been required for NPCs to have those fields set to FF in the spawn struct if the race didn't get those features. I don't think that is the case anymore. As far as I can tell, NPC facial features work perfectly no matter if we use the 99 and 0xFF stuff or not.

Anyway, I am still trying to figure out exactly what is happening to cause the weird issues with features. I still think things are being way overcomplicated and if they are simplified, should work just fine. So far in SoF, I think all features work perfectly with the exception of hair. For some reason, Hairstyle doesn't want to play friendly at the character select screen in SoF. Apparently when I create a character, no matter what I set hair to, it either isn't saving the field properly, or isn't pulling it properly. It may be something to do with the field being named "hair" instead of "hairstyle" in the character_select structure. That is the only field that doesn't match up with the names in the player profile structure and coincidentally is the only field that is giving me problems in SoF character select.

If I can't make some good breakthrough on it tonight, I might just have to revert the change I already put into mob.cpp the other night, at least for now.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #22  
Old 05-14-2009, 07:40 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Ok, I think I got it mostly figured out and working. So far, it seems like titanium character select is 100% accurate, but in game, beards aren't working quite properly though everything else seems good as far as I can tell.

On SoF, it is almost the opposite; character select shows all characters as bald (after they have logged in game at least once). But, in game on SoF, all facial features seem to be 100% and facechange also seems to work 100% as far as I have tested.

I really have no clue yet why hair isn't working properly in SoF character select. It just doesn't make sense that it shows hair properly before logging in for the first time and then not again after that. In game is the most important part, so it is good that it is working properly at least.

I find it interesting that beards are what seem to be having trouble in Titanium now. In the past, it was always hair issues, so for it to switch and now be a beard issue is pretty odd.

My best guess is that some struct stuff must be off, causing the wrong values to get saved to the wrong place. If something is off on SoF, I think it almost has to be the hairstyle field in the character select (and maybe character create) struct. And if it is a struct issue on Titanium causing Titanium issues, it seems like it might be the facechange struct and maybe even the spawn struct.

I have the changes I made so far up on the SVN. I did quite a few changes, but most of it was just renaming "hair" to "hairstyle" for the character select struct and cleaning up code a little here and there. The actual changes that effect how facial features work weren't that big of changes, so it would be easy to revert them if needed.

I think as long as we keep looking into it, we can get this issue resolved the right way once and for all. Once the current features are working properly, we can start trying to get the new Drakkin features added in. I just didn't want to try to add in new stuff into a hack. Would rather have it done the right way

***EDIT***

Actually, after thinking about it, I noticed that sometimes hairstyle would show up in SoF on character select, but only if I set the hair color really low (light brown or so). I then noticed that one of them wasn't even using the right hairstyle that I had set. Figured out that the issue was with the character select struct on SoF having haircolor and hairstyle in the reverse positions. I swapped them and now SoF is working 100% for facial features as far as I can tell. I also had to swap them in character creation, but it all seems to work flawless now! Ready for Drakkin features now, I think. But, I am going to see if I can get Titanium fixed fully first if possible.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 05-14-2009 at 04:17 PM..
Reply With Quote
  #23  
Old 05-14-2009, 11:22 AM
Shendare
Dragon
 
Join Date: Apr 2009
Location: California
Posts: 814
Default

LOL, exciting times.

I just wish there were more hours in the day. Work's been keeping me too busy to be able to mess with things for more than an hour or so a day.
Reply With Quote
  #24  
Old 05-14-2009, 09:31 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

After what I have seen in my testing so far, and after thinking about it more last night before bed, I am suspecting that the issue with Titanium is that one of the facial feature fields are off in one or more than one of the Titanium structures. My biggest suspects are the Player Profile and the Spawn structure. I am 99% positive that SoF now has the proper field identification for all facial feature related structures. So, I should be able to use SoF as a reference for what NPCs should look like when the fields are correct. Then, if needed, I can use Shendare's test code for the Titanium spawn struct and see if we might have some fields backwards or in the wrong place. My guess is that beard and beard color might be reversed in the spawn struct or player profile or both.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
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 09:59 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