View Single Post
  #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