View Single Post
  #1  
Old 06-21-2009, 06:54 PM
Shendare
Dragon
 
Join Date: Apr 2009
Location: California
Posts: 814
Cool Armor Tint Deluxe

Okay, I wasn't satisfied with a single armor_tint value for an NPC's entire outfit. I wanted the ability to specify colors for individual armor pieces, so I could create colored armor uniforms for guards and such, potentially replacing old low-poly guards with Luclin models.

It wasn't too horribly difficult.



SQL change:
Code:
ALTER TABLE `npc_types` ADD COLUMN `armortint_id` INTEGER UNSIGNED NOT NULL DEFAULT 0 AFTER `drakkin_details`;
SQL table addition:
Code:
CREATE TABLE `npc_types_tint` (
  `id` int unsigned NOT NULL DEFAULT '0',
  `red1h` tinyint unsigned NOT NULL DEFAULT '0',
  `grn1h` tinyint unsigned NOT NULL DEFAULT '0',
  `blu1h` tinyint unsigned NOT NULL DEFAULT '0',
  `red2c` tinyint unsigned NOT NULL DEFAULT '0',
  `grn2c` tinyint unsigned NOT NULL DEFAULT '0',
  `blu2c` tinyint unsigned NOT NULL DEFAULT '0',
  `red3a` tinyint unsigned NOT NULL DEFAULT '0',
  `grn3a` tinyint unsigned NOT NULL DEFAULT '0',
  `blu3a` tinyint unsigned NOT NULL DEFAULT '0',
  `red4b` tinyint unsigned NOT NULL DEFAULT '0',
  `grn4b` tinyint unsigned NOT NULL DEFAULT '0',
  `blu4b` tinyint unsigned NOT NULL DEFAULT '0',
  `red5g` tinyint unsigned NOT NULL DEFAULT '0',
  `grn5g` tinyint unsigned NOT NULL DEFAULT '0',
  `blu5g` tinyint unsigned NOT NULL DEFAULT '0',
  `red6l` tinyint unsigned NOT NULL DEFAULT '0',
  `grn6l` tinyint unsigned NOT NULL DEFAULT '0',
  `blu6l` tinyint unsigned NOT NULL DEFAULT '0',
  `red7f` tinyint unsigned NOT NULL DEFAULT '0',
  `grn7f` tinyint unsigned NOT NULL DEFAULT '0',
  `blu7f` tinyint unsigned NOT NULL DEFAULT '0',
  `red8x` tinyint unsigned NOT NULL DEFAULT '0',
  `grn8x` tinyint unsigned NOT NULL DEFAULT '0',
  `blu8x` tinyint unsigned NOT NULL DEFAULT '0',
  `red9x` tinyint unsigned NOT NULL DEFAULT '0',
  `grn9x` tinyint unsigned NOT NULL DEFAULT '0',
  `blu9x` tinyint unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
Notes:

- I don't know if the table specs (engine, row_format, etc.) are the best ones to use. They were just the defaults used with my MySQL installation.

- Field numberings are Helm, Chest, Arms, Bracers, Gloves, Legs, then Face. The letters after the numbers can help if you're editing the table data directly. 8 and 9 are for Primary and Secondary weapon slots, and as far as I can tell are unused by the client at this time. They can be left at 0.

Server Code changes:

eq_packet_structs.h - Line 1868
Code:
...
  /*085*/  uint8  haircolor;    // Verified
- /*085*/  uint8  beard;      // Verified
+ /*086*/  uint8  beard;      // Verified
  /*087*/  uint8  beardcolor;    // Verified
  /*088*/  uint32  drakkin_heritage;  // Temp Placeholder until field is identified in SoF
  /*092*/  uint32  drakkin_tattoo;    // Temp Placeholder until field is identified in SoF
  /*096*/  uint32  drakkin_details;  // Temp Placeholder until field is identified in SoF
- /*100*/  uint32  armor_tint;    // Temp Placeholder until field is identified in SoF
- /*104*/  uint8  eyecolor1;    // Temp Placeholder until field is identified in SoF
- /*105*/  uint8  eyecolor2;    // Temp Placeholder until field is identified in SoF
- /*106*/  uint8  unknown106[150];  //was uint8  unknown021[168];
+ /*100*/  uint32  armor_tint[MAX_MATERIALS];    // Temp Placeholder until field is identified in SoF
+ /*136*/  uint8  eyecolor1;    // Temp Placeholder until field is identified in SoF
+ /*137*/  uint8  eyecolor2;    // Temp Placeholder until field is identified in SoF
+ /*138*/  uint8  unknown138[118];  //was uint8 unknown106[150]; //was uint8  unknown021[168];
  /*256*/
  };
...
mob.h - Line 374
Code:
...
  int32  in_drakkin_details,
- int32  in_armor_tint,
+ int32  in_armor_tint[MAX_MATERIALS],
  int8   in_aa_title,
...
mob.h - Line 535
Code:
...
  inline int8  GetDrakkinDetails()      const { return drakkin_details; }
- inline int32  GetArmorTint()      const { return armor_tint; }
+ inline int32  GetArmorTint(int8 i)      const { return armor_tint[(i < MAX_MATERIALS) ? i : 0]; }
  inline int8  GetClass()          const { return class_; }
...
mob.h - Line 726
Code:
...
  void  TryDotCritical(int16 spell_id, Mob *caster, int &damage);

- void  SendIllusionPacket(int16 in_race, int8 in_gender = 0xFF, int16 in_texture = 0xFFFF, int16 in_helmtexture = 0xFFFF, int8 in_haircolor = 0xFF, int8 in_beardcolor = 0xFF, int8 in_eyecolor1 = 0xFF, int8 in_eyecolor2 = 0xFF, int8 in_hairstyle = 0xFF, int8 in_luclinface = 0xFF, int8 in_beard = 0xFF, int8 in_aa_title = 0xFF, int32 in_drakkin_heritage = 0xFFFFFFFF, int32 in_drakkin_tattoo = 0xFFFFFFFF, int32 in_drakkin_details = 0xFFFFFFFF, int32 in_armor_tint = 0xFFFFFFFF);
+ void  SendIllusionPacket(int16 in_race, int8 in_gender = 0xFF, int16 in_texture = 0xFFFF, int16 in_helmtexture = 0xFFFF, int8 in_haircolor = 0xFF, int8 in_beardcolor = 0xFF, int8 in_eyecolor1 = 0xFF, int8 in_eyecolor2 = 0xFF, int8 in_hairstyle = 0xFF, int8 in_luclinface = 0xFF, int8 in_beard = 0xFF, int8 in_aa_title = 0xFF, int32 in_drakkin_heritage = 0xFFFFFFFF, int32 in_drakkin_tattoo = 0xFFFFFFFF, int32 in_drakkin_details = 0xFFFFFFFF, int32* in_armor_tint = 0);

  static  int32  GetAppearanceValue(EmuAppearance iAppearance);
...
mob.h - Line 1162
Code:
...
  int32  drakkin_details;
- int32  armor_tint;
+ int32  armor_tint[MAX_MATERIALS];

  int8  aa_title;
...
mob.cpp - Line 89
Code:
...
  int32  in_drakkin_details,
- int32  in_armor_tint,
+ int32  in_armor_tint[MAX_MATERIALS],

  int8   in_aa_title,
...
mob.cpp - Line 187
Code:
...
  drakkin_details    = in_drakkin_details;
- armor_tint = in_armor_tint;
  attack_speed = 0;
...
mob.cpp - Line 249
Code:
...
  }

+ for (i = 0; i < MAX_MATERIALS; i++)
+ {
+   if (in_armor_tint)
+   {
+     armor_tint[i] = in_armor_tint[i];
+   }
+   else
+   {
+     armor_tint[i] = 0;
+   }
+ }

  delta_heading = 0;
...
mob.cpp - Line 792
Code:
...
    ns->spawn.equipment[i] = GetEquipmentMaterial(i);
-   if (armor_tint)
-   {
-      ns->spawn.colors[i].color = armor_tint;
-   }
+   if (armor_tint[i])
+   {
+      ns->spawn.colors[i].color = armor_tint[i];
+   }
    else
    {
      ns->spawn.colors[i].color = GetEquipmentColor(i);
    }
  }
...
mob.cpp - Line 1164
Code:
...
- void Mob::SendIllusionPacket(int16 in_race, int8 in_gender, int16 in_texture, int16 in_helmtexture, int8 in_haircolor, int8 in_beardcolor, int8 in_eyecolor1, int8 in_eyecolor2, int8 in_hairstyle, int8 in_luclinface, int8 in_beard, int8 in_aa_title, int32 in_drakkin_heritage, int32 in_drakkin_tattoo, int32 in_drakkin_details, int32 in_armor_tint) {
+ void Mob::SendIllusionPacket(int16 in_race, int8 in_gender, int16 in_texture, int16 in_helmtexture, int8 in_haircolor, int8 in_beardcolor, int8 in_eyecolor1, int8 in_eyecolor2, int8 in_hairstyle, int8 in_luclinface, int8 in_beard, int8 in_aa_title, int32 in_drakkin_heritage, int32 in_drakkin_tattoo, int32 in_drakkin_details, int32* in_armor_tint) {
...
mob.cpp - Line 1209
Code:
...
  this->helmtexture = in_helmtexture;

+ int i;

  if (in_race > 12 && in_race != 128 && in_race != 130 && in_race != 330 && in_race != 522) {
...
mob.cpp - Line 1223
Code:
...
    this->drakkin_details = 0xFFFFFFFF;
-   this->armor_tint = 0xFFFFFFFF;
+   for (i = 0; i < MAX_MATERIALS; i++)
+   {
+     this->armor_tint[i] = 0xFFFFFFFF;
+   }

  }
...
mob.cpp - Line 1282
Code:
...
    this->drakkin_details = in_drakkin_details;

-   if (in_armor_tint == 0xFFFFFFFF)
-     this->armor_tint = GetArmorTint();
-   else
-     this->armor_tint = in_armor_tint;    

+   for (i = 0; i < MAX_MATERIALS; i++)
+   {
+     if ((in_armor_tint) && (in_armor_tint[i]))
+       this->armor_tint[i] = in_armor_tint[i];
+     else
+       this->armor_tint[i] = GetArmorTint(i);
+   }
    
  }
...
mob.cpp - Line 1308
Code:
...
    this->drakkin_details = CastToClient()->GetBaseDetails();
-   this->armor_tint = 0xFFFFFFFF;
+   for (i = 0; i < MAX_MATERIALS; i++)
+   {
+     this->armor_tint[i] = 0xFFFFFFFF;
+   }
  }
...
mob.cpp - Line 1334
Code:
...
    is->drakkin_details = this->drakkin_details;
-   is->armor_tint = this->armor_tint;
+   for (i = 0; i < MAX_MATERIALS; i++)
+   {
+     is->armor_tint[i] = this->armor_tint[i];
+   }
  
    DumpPacket(outapp);
...
npc.cpp - Line 97
Code:
...
    d->drakkin_details,
-   d->armor_tint,
+   (int32*)d->armor_tint,
    0,
...
zonedump.h - Line 89
Code:
...
    int32  drakkin_details;
-   int32  armor_tint;
+   int32  armor_tint[MAX_MATERIALS];
//  int8  aa_title;  ////not loaded from DB
...
zonedb.cpp - Line 1053
Code:
...
      "npc_types.drakkin_details,"
+     "npc_types.armortint_id,"
      "npc_types.armortint_red,"
...
zonedb.cpp - Line 1144
Code:
...
        tmpNPCType->drakkin_details = atoi(row[r++]);

-       tmpNPCType->armor_tint = (atoi(row[r++]) & 0xFF) << 16;
-       tmpNPCType->armor_tint |= (atoi(row[r++]) & 0xFF) << 8;
-       tmpNPCType->armor_tint |= (atoi(row[r++]) & 0xFF);
-       tmpNPCType->armor_tint |= (tmpNPCType->armor_tint) ? (0xFF << 24) : 0;

+       uint32 armor_tint_id = atoi(row[r++]);
+       tmpNPCType->armor_tint[0] = (atoi(row[r++]) & 0xFF) << 16;
+       tmpNPCType->armor_tint[0] |= (atoi(row[r++]) & 0xFF) << 8;
+       tmpNPCType->armor_tint[0] |= (atoi(row[r++]) & 0xFF);
+       tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
+
+       int i;
+       if (armor_tint_id > 0)
+       {
+         if (tmpNPCType->armor_tint[0] == 0)
+         {
+           char at_errbuf[MYSQL_ERRMSG_SIZE];
+           char *at_query = NULL;
+           MYSQL_RES *at_result = NULL;
+            MYSQL_ROW at_row;
+            
+            MakeAnyLenString(&at_query,
+             "SELECT "
+             "red1h,grn1h,blu1h,"
+             "red2c,grn2c,blu2c,"
+             "red3a,grn3a,blu3a,"
+             "red4b,grn4b,blu4b,"
+             "red5g,grn5g,blu5g,"
+             "red6l,grn6l,blu6l,"
+             "red7f,grn7f,blu7f,"
+             "red8x,grn8x,blu8x,"
+             "red9x,grn9x,blu9x "
+             "FROM npc_types_tint WHERE id=%d", armor_tint_id);
+
+           if (RunQuery(at_query, strlen(at_query), at_errbuf, &at_result))
+           {
+             if ((at_row = mysql_fetch_row(at_result)))
+             {
+               for (i = 0; i < MAX_MATERIALS; i++)
+               {
+                 tmpNPCType->armor_tint[i] = atoi(at_row[i * 3]) << 16;
+                 tmpNPCType->armor_tint[i] |= atoi(at_row[i * 3 + 1]) << 8;
+                 tmpNPCType->armor_tint[i] |= atoi(at_row[i * 3 + 2]);
+                  tmpNPCType->armor_tint[i] |= (tmpNPCType->armor_tint[i]) ? (0xFF << 24) : 0;
+               }
+             }
+             else
+             {
+               armor_tint_id = 0;
+             }
+           }
+           else
+           {
+             armor_tint_id = 0;
+           }
+
+           if (at_result)
+           {
+              mysql_free_result(at_result);
+            }
+            
+           safe_delete_array(at_query);
+         }
+         else
+         {
+           armor_tint_id = 0;
+         }
+       }
+
+       if (armor_tint_id == 0)
+       {
+         for (i = 1; i < MAX_MATERIALS; i++)
+         {
+           tmpNPCType->armor_tint[i] = tmpNPCType->armor_tint[0];
+         }
+       }

        tmpNPCType->see_invis = atoi(row[r++])==0?false:true;      // Set see_invis flag
...
I think that got everything.

Last edited by trevius; 06-22-2009 at 01:11 PM.. Reason: Changed zonedb.h to zonedump.h
Reply With Quote