|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
06-21-2009, 06:54 PM
|
Dragon
|
|
Join Date: Apr 2009
Location: California
Posts: 814
|
|
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
|
|
|
|
06-21-2009, 07:30 PM
|
Dragon
|
|
Join Date: Apr 2009
Location: California
Posts: 814
|
|
Forgot to clarify. This is the order of priority for armor tints:
1. armortint_red, _green, and _blue in npc_types. If any of these values is non-zero, the tint is applied to all armor pieces, ignoring armortint_id and individual armor piece coloring.
2. armortint_id. If the RGB values in #1 are all 0 but armortint_id is specified, the values from the npc_types_tint table with the corresponding id are used.
3. armor piece tint. If the RGB values in 1 are zero and armortint_id is 0 (or a corresponding record in npc_types_tint cannot be found), or if the red/grn/blu values for a particular armor piece in npc_types_tint are all 0, the tint on the actual armor piece item is displayed.
Hope that clears up any potential confusion.
|
06-21-2009, 08:16 PM
|
|
Demi-God
|
|
Join Date: Mar 2009
Location: Umm
Posts: 1,492
|
|
AWSOME...
stupid question but to say to truly replicate the old felguard - he actual needs to wear CHAIN arms - how would you achieve that?
ALSO:
"Helm, Chest, Arms, Bracers, Gloves, Legs, then Face."
Face? but no Boots?
|
06-21-2009, 09:09 PM
|
Dragon
|
|
Join Date: Apr 2009
Location: California
Posts: 814
|
|
Err... I actually typed that? LOL.
Feet. The 'F' is for feet.
And really, mixing armor types doesn't work out well. The armor meshes were designed to match up together, and they look out of place when mixed and matched. Better to stick with all chain, all plate, all leather, or all cloth.
|
|
|
|
06-21-2009, 09:32 PM
|
|
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
That is really awesome, Shendare! ChaosSlayer, I think Shendare meant to say "foot", not "face", since helm was already listed and that would be the same as face.
I will try to get this added ASAP. One thing I wanted to mention is that I don't think armor tint can be sent with an illusion packet, but it should be able to be sent with a wearchange packet. So, I need to go through and write a command or 2 that will use the wearchange packets for changing armor tints or weapons without having to repop the zone/NPC. I don't think it will be too hard to get that coded and I will probably start soon after I get AAs for SoF all figured out and finalized. I will probably try to add in a quest command or 2 for handling armor changes Then we would be able to change out armor on playable races, or we could even swap out weapons on other races mid-fight. Might be cool to have guards that normally have no weapons showing and then they whip them out when they aggro on something, or anything along those lines.
I really like how you made a separate table for handling the new armor settings. I am surprised Live doesn't have anything like this, but maybe they will steal the idea when they see it :P
I do think we could also include a material field for each slot in that table. Then, we could have it send the material for each slot so you could have NPCs with mismatched set pieces like ChaosSlayer suggested.
This is some nice stuff, Shendare I don't know why, but I have been really happy with the illusion and spawn struct stuff we have figure out so far. I guess they are just things that have always bothered me just enough to stay on my radar. It is really nice to finally be working all of this stuff out so it never has to be messed with again other than maybe adding in more commands to use them.
|
|
|
|
06-21-2009, 09:42 PM
|
|
Demi-God
|
|
Join Date: Mar 2009
Location: Umm
Posts: 1,492
|
|
yeah I kind of figured it was a mistype, since helm was allreday listed, and for a moment I was wondering - "what? he managed to tint the FACE too?"
As far as diffirent materials go - didn't just recently someone wrote a perl script which can ultra randomize npc when it spawns? Like face, hair, and specificly armor by slot? Or it was just something someone wanted to do?
Quote:
I am surprised Live doesn't have anything like this, but maybe they will steal the idea when they see it :P
|
LIVE sucks =) Honestly when I look back at early EQ days it kills me how UNCREATIVE the original team was. Some basic natural things which are directly obvious took them years to put in, and not untill SOE took over..
|
06-21-2009, 09:45 PM
|
Dragon
|
|
Join Date: Apr 2009
Location: California
Posts: 814
|
|
Yeah, it's cool, Trev!
I'm not sure exactly what you're unsure of regarding the illusion packets, but the code there in mob.cpp from lines 1164-1350 or so is in SendIllusionPacket().
I can change an NPC's race and gender in-game and the armor tints carry over to the new model, and it was my understanding that you use SendIllusionPacket when changing these in-game.
|
|
|
|
06-21-2009, 10:40 PM
|
|
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Shendare, I added the armor tint stuff to that command because there is a large part of the illusion packet that we don't have identified yet and I assume that part of it may for armor and tint. I tried to identify those parts and was able to find some helms (some of which showed up as sideway), but I could never exactly figure out what was going on. It is probably because the test I was using is your test code, but it is in int8 and I assume armor would need int32 instead. I just never tried it to see if that was the case.
On a side note, I also noticed that most races cannot change their hair style when using illusion packets. I have no idea why this is, but I can only get Drakkin, Humans, and Female Ogres to change their hairstyle using Illusion packets. The other races all just set their hair to 0 or something. This one has stumped me and may just be an issue with the client (I really only use SoF), so I just gave up on the hair thing.
I will just have to mess with the wearchange packets and get something similar setup for them. I was able to get it to keep the current texture they had on by just not sending anything for the texture/helm fields of the illusion struct. To be able to change armor without repops, it would probably take wearchanges to do it.
ChaosSlayer, it was me that recently added the #randomfeatures command. But, that command only randomizes facial features like hair, beard, haircolor, tattoo and so on. It doesn't randomize armor, but that is a command I would like to add at some point. I wouldn't want it to make completely random armor for entire sets, but maybe using some sort of logic that has chances to make certain random changes that might look good together. The basic idea would be for it to be able to make armor sets similar to the guard one that Shendare posted in the first post. It would definitely take some playing around to make it output halfway decent sets most of the time.
I also really need to create a way to update an NPCs features and armor set/tint. Maybe the #npcspawn command can be expanded with a new option that would let you save the current race, gender, texture, features, armor and armor tint and so on of the current NPC you have targeted. So, you could use the randomizing commands until you found one that looked right and then just save it as it is.
I really have to at least knock out the SoF AA stuff first and maybe the newly added SoF item stats as well. So, I am not sure when I will be able to get to that. I will definitely try to get this tested and added to the code soon if someone doesn't beat me to it.
Last edited by trevius; 06-22-2009 at 06:43 AM..
|
|
|
|
|
|
|
06-21-2009, 11:42 PM
|
|
Demi-God
|
|
Join Date: Mar 2009
Location: Umm
Posts: 1,492
|
|
Quote:
Originally Posted by trevius
ChaosSlayer, it was me that recently added the #randomfeatures command. But, that command only randomizes facial features like hair, beard, haircolor, tattoo and so on. It doesn't randomize armor, but that is a command I would like to add at some point. I wouldn't want it to make completely random armor for entire sets, but maybe using some sort of logic that has chances to make certain random changes that might look good together. The basic idea would be for it to be able to make armor sets similar to the guard one that Shendare posted in the first post. It would definitely take some playing around to make it output halfway decent sets most of the time.
|
Trev if this case, what we realy need is something like:
quest::npcarmor(slot, material);
so its not random, but rather specific by user wish.
If you do want it random you just do RND on material for specific/all slots
then we don't need to have to put it into DB
|
|
|
|
06-22-2009, 05:16 AM
|
|
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
ChaosSlayer, before I add another random command, I would definitely add the direct command for changing stuff like that. The random command would just be another bonus command to go along with it. First would be one for changing tint, then maybe one for changing the material of each slot, and yet another for changing weapons out. Last and most importantly is to create a command that let's a dev save the current looks from in game. Actual # commands would be added first and then those could be copied to create quest:: commands as well whenever.
Last edited by trevius; 06-22-2009 at 01:41 PM..
|
06-22-2009, 05:58 AM
|
|
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
This has now been added to Revision 702 on the SVN.
This feature is awesome BTW! Playing with it shows that it has a ton of potential. The only thing I might add in soon is a simple notes field for the table so you can name each armor set. This way, you can easily have different colored sets and just name them to use them anywhere. It would make managing a large amount of sets quite a bit easier.
Last edited by trevius; 06-22-2009 at 04:13 PM..
|
06-22-2009, 10:39 AM
|
Dragon
|
|
Join Date: Apr 2009
Location: California
Posts: 814
|
|
Agreed, a name field is a very good idea! Don't know how I missed it.
|
06-22-2009, 10:52 AM
|
Dragon
|
|
Join Date: May 2006
Location: Cincinnati, OH
Posts: 689
|
|
I just wanted to take a minute and chime in to say how amazing your work has been. Thanks for this splendid ability to add some real customization =)
|
06-22-2009, 11:32 AM
|
Dragon
|
|
Join Date: Apr 2009
Location: California
Posts: 814
|
|
Thanks, it's good to feel appreciated.
|
06-22-2009, 01:43 PM
|
Discordant
|
|
Join Date: Jan 2002
Posts: 305
|
|
Quote:
Originally Posted by Shendare
Thanks, it's good to feel appreciated.
|
I have to second his remarks. Your additions to the project have been invaluable. If anyone's earned the rank of Developer, it's you!
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 09:20 AM.
|
|
|
|
|
|
|
|
|
|
|
|
|