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
  #1  
Old 05-15-2009, 07:24 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

All Drakkin Specific Features are now in! This includes for both NPCs and PCs! Even Drakkin Corpses seem to appear perfectly after a zone dump.

I didn't really want to have to do this all at one time, but there were so many things to change that I finally just went ahead and did them all so that it finishes it without causing possible issues. As far as I can tell, it seems that there are no issues with this change, but there was so much stuff that I had to change that it is possible something might have gotten messed up. Let's hope not, though!

I wound up saving the new Drakkin features to the player profile after-all. It was just easier for me to figure out and to do it the same as all other facial features were. I also added in the new drakkin_heritage, drakkin_tattoo, and drakkin_details fields to the npc_types table right after luclin_beard.

I tested both SoF and Titanium and now they both seem to be flawless for all player race feature settings and I don't see anymore issues. If there aren't anymore issues, I will be very glad to have this one thing all done with!

Also, I wanted to note that I have not identified the drakkin related fields in the SoF player profile. But, apparently, they aren't even required. It just sends the char info packet that overwrites anything that the PP would send. There are many things in the PP that get ignored by the client due to other packets handling and overriding anything that the PP had sent for them. It wouldn't hurt to identify these fields in the PP for SoF, but unless there is some real reason to do so, I don't think we need to worry about it at all.

Please let me know if anyone is seeing issues with the latest SVN updates in relations to facial features. As mentioned, players will have to redo their looks in game if they have changed. That only needs to be set 1 time, though. Any other issues should be reported here if possible.

Here are some Drakkin examples with different Heritages, Tattoos, and Details:





Big thanks for Shendare for the help

Now with this stuff all working properly, maybe I can figure out what to do to get the illusion function working for all facial features. Once that works, I am going to try to get #fixmob working for all facial features. So, when you spawn a mob, you will be able to quickly and easily cycle through features before saving it to the database. This way you get it set perfectly while in game much quicker than currently possible. It would be nice to get NPC armor tint in there as well, but I probably won't mess with that for a long time.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 05-15-2009 at 03:50 PM..
Reply With Quote
  #2  
Old 05-15-2009, 01:11 PM
vales
Discordant
 
Join Date: May 2006
Posts: 458
Default

Nice work guys!
Reply With Quote
  #3  
Old 05-16-2009, 08:48 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

I got the support for the new features added to the illusion function, but the fields will still need to be identified in the SoF illusion_struct before we can use any of the new fields. It would be cool to identify armor tint in there as well, because I am pretty sure it is in there somewhere and then we could use it for setting the new armor tint stuff from in game.

I started work on updating the #fixmob command, but I suck at coding from scratch. I can't get it to compile this yet because of the case settings, and I don't really know how to do the switch from the command argument properly.

Here is what I have so far to rewrite it so that it doesn't get ridiculously long when I add in the other features. It will still be long, but the old way was just WAY too long lol.

Code:
void command_fixmob(Client *c, const Seperator *sep)
{
	Mob *target=c->GetTarget();

	if (!sep->arg[1])
		c->Message(0,"Usage: #fixmob [nextrace|prevrace|gender|nexttexture|prevtexture|nexthelm|prevhelm]");
	else if (!target)
		c->Message(0,"Error: this command requires an NPC target");
	else {

		int16 Race = target->GetRace();
		int8 Gender = target->GetGender();
		int8 Texture = target->GetTexture();
		int8 HelmTexture = target->GetHelmTexture();
		int8 HairColor = target->GetHairColor();
		int8 BeardColor = target->GetBeardColor();
		int8 EyeColor1 = target->GetEyeColor1();
		int8 EyeColor2 = target->GetEyeColor2();
		int8 HairStyle = target->GetHairStyle();
		int8 LuclinFace = target->GetLuclinFace();
		int8 Beard = target->GetBeard();
		int32 DrakkinHeritage = target->GetDrakkinHeritage();
		int32 DrakkinTattoo = target->GetDrakkinTattoo();
		int32 DrakkinDetails = target->GetDrakkinDetails();
		char ChangeType;
		int32 ChangeSetting;
		
		switch(sep->arg[1]) {
			case nextrace:
			{
				if(Race == 586)
					Race = 0;
				else
					Race = Race + 1;
				ChangeType = "Race";
				ChangeSetting = Race;
				break;
			}
			case prevrace:
			{
				if(Race == 0)
					Race = 586;
				else
					Race = Race - 1;
				ChangeType = "Race";
				ChangeSetting = Race;
				break;
			}
			case gender:
			{
				if(Gender == 2)
					Gender = 0;
				else
					Gender = Gender + 1;
				ChangeType = "Gender";
				ChangeSetting = Gender;
				break;
			}		
			case nexttexture:
			{
				if(Texture == 25)
					Texture = 0;
				else
					Texture = Texture + 1;
				ChangeType = "Texture";
				ChangeSetting = Texture;
				break;
			}
			case prevtexture:
			{
				if(Texture == 0)
					Texture = 25;
				else
					Texture = Texture - 1;
				ChangeType = "Texture";
				ChangeSetting = Texture;
				break;
			}
			case nexthelm:
			{
				if(HelmTexture == 25)
					HelmTexture = 0;
				else
					HelmTexture = HelmTexture + 1;
				ChangeType = "HelmTexture";
				ChangeSetting = HelmTexture;
				break;
			}
			case prevhelm:
			{
				if(HelmTexture == 0)
					HelmTexture = 25;
				else
					HelmTexture = HelmTexture - 1;
				ChangeType = "HelmTexture";
				ChangeSetting = HelmTexture;
				break;
			}
		
		
		}
		target->SendIllusionPacket(Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
				EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
				DrakkinHeritage, DrakkinTattoo, DrakkinDetails);
				
		c->Message(0, "%c=%i", ChangeType, ChangeSetting);
	}

}
Anyone wanna help me figure out what I am doing wrong with that case switch? Seems like I should be getting close to something that would work to replace the current code for the command as it is. I am sure I could get this stuff in the long way, but it would just make more very ugly coding.

Once this is working for the current #fixmob arguments, I will get the others added in. Then, we will just need to identify the rest of the SoF illusion struct and we should be set. As a bonus, I bet we could get that new armor tint setting working in this afterward, but I don't really know much about breaking the separate color fields out of the single armortint int32 field.

The new illusion function features are on the SVN already, so this stuff should be fairly easy to add in once it is written properly.

Also, I was thinking it would probably be a good idea to add in some commands to set the new features similar to the #texture command. I know #face has been in the code and not working forever, but I bet I can probably fix that pretty easily now lol.

###EDIT###

Went ahead and tried implementing #face and it seems to work fine and wasn't hard at all to add. I think we can probably just do the same thing for the other features. The #face command was already in, but wasn't coded properly. Here is the correct code to change it to in the command.cpp:

Code:
void command_face(Client *c, const Seperator *sep)
{
	Mob *target=c->GetTarget();
	if (!sep->IsNumber(1))
		c->Message(0,"Usage: #face [number of face]");
	else if (!target)
		c->Message(0,"Error: this command requires a target");
	else {
		target->SendIllusionPacket(0, 255, 255, 255, 255, 255, 255, 255, 255, atoi(sep->arg[1]));
		c->Message(0,"Face = %i", atoi(sep->arg[1]));
	}
}
That seems to work anyway. I will get this added with my next SVN update. May have to play with it a bit to make sure it can maintain previous settings when changing face, though.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!

Last edited by trevius; 05-16-2009 at 05:34 PM..
Reply With Quote
  #4  
Old 05-16-2009, 01:12 PM
Shendare
Dragon
 
Join Date: Apr 2009
Location: California
Posts: 814
Default

Edit: Oops. Reworking.
Reply With Quote
  #5  
Old 05-16-2009, 02:13 PM
Shendare
Dragon
 
Join Date: Apr 2009
Location: California
Posts: 814
Default

Okay. Originally I'd taken the original function and simplified it to make it very fast and efficient, and it even let you use shortcuts to shrink the command down to one or two digits (nh for nexthelm, pt for prevtexture, etc.).

Then I saw what you were doing with your actual post, giving the option to change more fields with the #fixmob command than the existing ones, and the shortcuts and such wouldn't work out.

So, back to the original question, the main issue with with your code is that C++ does not support using the switch statement with strings (like Javascript, C#, etc, do). It only works with numbers and single chars.

Here's a reworked version of your code that runs efficiently and has plenty of room for expansion with new commands:

Code:
void command_fixmob(Client *c, const Seperator *sep)
{
  Mob *target=c->GetTarget();
  char* Usage = "Usage: #fixmob [gender]|[(next/prev)race|texture|helm|hairstyle|haircolor]";

  if (!sep->arg[1])
    c->Message(0,Usage);
  else if (!target)
    c->Message(0,"Error: this command requires an NPC target");
  else
  {
    int16 Race = target->GetRace();
    int8 Gender = target->GetGender();
    int8 Texture = target->GetTexture();
    int8 HelmTexture = target->GetHelmTexture();
    int8 HairColor = target->GetHairColor();
    int8 BeardColor = target->GetBeardColor();
    int8 EyeColor1 = target->GetEyeColor1();
    int8 EyeColor2 = target->GetEyeColor2();
    int8 HairStyle = target->GetHairStyle();
    int8 LuclinFace = target->GetLuclinFace();
    int8 Beard = target->GetBeard();
    int32 DrakkinHeritage = target->GetDrakkinHeritage();
    int32 DrakkinTattoo = target->GetDrakkinTattoo();
    int32 DrakkinDetails = target->GetDrakkinDetails();
    
    char* ChangeType = NULL; // If it's still NULL after processing, they didn't send a valid command
    int32 ChangeSetting;
    char* command = sep->arg[1];
    char codeMove;
    char codeType;

    codeMove = (command[0] | 0x20); // First character, lower-cased
    if (strlen(command) > 4)
    {
      codeType = command[4] | 0x20; // Fifth character, lower-cased
    }
    else
    {
      codeType = NULL;
    }

    if (codeMove == 'g')
    {
      // Gender doesn't start with next/prev, so the first char is actually the type
      codeType = codeMove;
    }

    switch (codeType)
    {
      case 'g': // Gender
        if (strcasecmp(command, "gender") == 0)
        {
          Gender = (Gender == 2) ? 0 : Gender + 1; // 0 - 2
          ChangeType = "Gender";
          ChangeSetting = Gender;
        }
        break;
      case 'r': // Race
        switch (codeMove)
        {
          case 'n': // Next
            if (strcasecmp(command, "nextrace") == 0)
            {
              Race = (Race == 586) ? 0 : Race + 1; // 0 - 586
              ChangeType = "Race";
              ChangeSetting = Race;
            }
            break;
          case 'p': // Prev
            if (strcasecmp(command, "prevrace") == 0)
            {
              Race = (Race == 0) ? 586 : Race - 1; // 0 - 586
              ChangeType = "Race";
              ChangeSetting = Race;
            }
            break;
        }
        break;
      case 't': // Texture
        switch (codeMove)
        {
          case 'n': // Next
            if (strcasecmp(command, "nexttexture") == 0)
            {
              Texture = (Texture == 25) ? 0 : Texture + 1; // 0 - 25
              ChangeType = "Texture";
              ChangeSetting = Texture;
            }
            break;
          case 'p': // Prev
            if (strcasecmp(command, "prevtexture") == 0)
            {
              Texture = (Texture == 0) ? 25 : Texture - 1; // 0 - 25
              ChangeType = "Texture";
              ChangeSetting = Texture;
            }
            break;
        }
        break;
      case 'h': // HelmTexture, HairStyle, HairColor
        switch (codeMove)
        {
          case 'n': // Next
            if (strcasecmp(command, "nexthelm") == 0)
            {
              HelmTexture = (HelmTexture == 25) ? 0 : HelmTexture + 1; // 0 - 25
              ChangeType = "HelmTexture";
              ChangeSetting = HelmTexture;
            }
            else if (strcasecmp(command, "nexthaircolor") == 0)
            {
              HairColor = (HairColor == 15) ? 0 : HairColor + 1; // 0 - 15
              ChangeType = "HairColor";
              ChangeSetting = HairColor;
            }
            else if (strcasecmp(command, "nexthairstyle") == 0)
            {
              HairStyle = (HairStyle == 7) ? 0 : HairStyle + 1; // 0 - 7
              ChangeType = "HairStyle";
              ChangeSetting = HairStyle;
            }
            break;
          case 'p': // Prev
            if (strcasecmp(command, "prevhelm") == 0)
            {
              HelmTexture = (HelmTexture == 0) ? 25 : HelmTexture - 1; // 0 - 25
              ChangeType = "HelmTexture";
              ChangeSetting = HelmTexture;
            }
            else if (strcasecmp(command, "prevhaircolor") == 0)
            {
              HairColor = (HairColor == 0) ? 15 : HairColor - 1; // 0 - 15
              ChangeType = "HairColor";
              ChangeSetting = HairColor;
            }
            else if (strcasecmp(command, "prevhairstyle") == 0)
            {
              HairStyle = (HairStyle == 0) ? 7 : HairStyle - 1; // 0 - 7
              ChangeType = "HairStyle";
              ChangeSetting = HairStyle;
            }
            break;
        }
        break;
      default:
        break;
    }

    if (ChangeType == NULL)
    {
      c->Message(0,Usage);
    }
    else
    {
      target->SendIllusionPacket(Race, Gender, Texture, HelmTexture, HairColor, BeardColor,
          EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF,
          DrakkinHeritage, DrakkinTattoo, DrakkinDetails);
        
      c->Message(0, "%s=%i", ChangeType, ChangeSetting);
    }
  }
}
I tested adding haircolor and hairstyle options.

Of course, options won't work if the illusion struct fields haven't been figured out.

I'll leave messing around with that one to you. Don't want to double up on your work. :P

- Shendare
Reply With Quote
  #6  
Old 05-16-2009, 11:17 PM
KLS
Administrator
 
Join Date: Sep 2006
Posts: 1,348
Default

By updating the struct inside the corpse's data field all old corpses are now prevented from spawning. In the future I'd probably avoid doing this if at all possible and if there's no other choice you need to provide a way for people to upgrade the corpses in a database (I'm writing this atm so don't worry about it).
Reply With Quote
  #7  
Old 05-17-2009, 12:19 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Yeah, as I have said elsewhere, this is my fault and I honestly didn't know it was going to happen. I didn't notice that there was a blob in the corpse tables. I thought it was just pulling the info from the PP. I had never attempted to do any changes like that before, so I really didn't know what I was doing. Honestly, I was hoping that someone more skilled would pick it up and add that stuff in at some point, but I know there are many other more important things to do. I figured I would try it and see if I could get them working and then just test it as best as I could to make sure there weren't issues with the changes. Unfortunately, I only tested newly created corpses, I didn't look for any old ones.

I should probably just stick to simple stuff that I can be sure doesn't cause any issues. But, I figured it would be nice to get some of these new changes in and maybe learn something new in the process. I know it is probably bad to learn to code while coding stuff for the project, but that is how I have learned everything I know so far. And, I normally try to test enough that it doesn't cause issues. Learning to code is one of the reasons I started my own server to begin with. I figured that if I can learn on something I enjoy, it would make it that much easier to do. Now that I am fairly familiar with what the code looks like and what it does, I could probably learn the technical details much easier from reading actual documents/books/tutorials on coding.
__________________
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:24 AM.


 

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