Implementing: AA/Character Traits

EQ2Emulator Development forum.

Moderator: Team Members

Post Reply
Jabantiz
Lead Developer
Posts: 2912
Joined: Wed Jul 25, 2007 2:52 pm
Location: California

Implementing: AA/Character Traits

Post by Jabantiz » Fri Oct 21, 2011 12:54 pm

I figured out the packet to populate the character traits list.
EQ2EmuCharTraits.png
(yes I know that is a necro spell in the swash grand master spell choices....)

I used packets from live and lucky for me 6118 client uses the same structure. I figured it out without looking at the WS_TraitsList struct then went to compare it after to see if I got close. The struct is almost the same except some things have misleading names for example

Code: Select all

<Data ElementName="trait_line" Type="int8" Size="1" />
Is the byte that tells you wich trait has been selected.

Now that I have figured this out I want to start working on the actual system to make this usable, but I will be the first to admit I suck at designing systems (mainy DB tables) I usually just start coding until I get the result I was looking for, so before I start I wanted to get feedback.

I figure the player should have a list of traits they have selected, and there should be a table for all the trait choices. Every thing on this page (racial abilities, racial traditions, character traits, and grand master spells) is sent in the same packet so should all of them be stored in the same table? As for the actual traits I would assume they would just go into the spell table?

So 2 new tables Character_traits (stores what choices the player made)

Code: Select all

CREATE TABLE `character_traits` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`char_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	`trait_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`id`),
	INDEX `FK_char_traits` (`char_id`),
	CONSTRAINT `FK_char_traits` FOREIGN KEY (`char_id`) REFERENCES `characters` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
and character_trait_choices (used to populate the page)

Code: Select all

CREATE TABLE `character_traits_choices` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`trait_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	`level` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	`race_req` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	`class_req` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`id`)
)
Like I said, I suck at designing tables so let me know if this is acceptable or if there is a better way to do this.
You do not have the required permissions to view the files attached to this post.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Character Traits

Post by John Adams » Fri Oct 21, 2011 1:20 pm

That is awesome, man! Congrats on getting into that packet ;) Zcoretri will have more accurate advice on the structs themselves, but as your DB guy...

the `character_traits` table may be a good idea, just to keep the data separate -- though we had discussed long ago about Traits really being perma-spells, so why not use character_spells? We can leave this open for discussion once you get further into the design. Honestly, it's however you want it to be, with many changes and requests by me right after you think you're done ;)

As for `character_trait_choices`, I am not sure what you mean by this table. Again, if they are put into the `spells` tables, we could just define them there - add fields necessary to supprot traits alone. What do you think?


Note also, we had also discussed separating Spells from AA's, and Traits, and Traditions all in their own sets of tables. That's how we do it in Parser right now, but as the DB Efficiency dude, I'd like to use what we got unless the data is SO different, regular Spells tables make no sense.

Again, Zcoretri spent a lot of time looking over this data, so we can wait for him to weigh in.

Good work! Thank you for doing this.
John Adams
EQ2Emulator - Project Ghost
"Everything should work now, except the stuff that doesn't" ~Xinux

Jabantiz
Lead Developer
Posts: 2912
Joined: Wed Jul 25, 2007 2:52 pm
Location: California

Re: Character Traits

Post by Jabantiz » Fri Oct 21, 2011 2:33 pm

I am not a database guy, I can get by but I have no idea what is best, just so you all know.

character_trait_choices was suppose to just be a list of the traits(spells) that are listed, but adding another field in spells would probably be better. Or would it be better to add a spell_traits table that is just the spell id of those spells that are traits so the spell table doesn't have a field that is not used for the vast majority of spells?

Just other info I am putting out there, each selection has 4 or 5 choices, can't be more or less. Also need a way to determine traits from class training and racial traditions (can probably do that by looking up spell class restriction for training, but is there a race restriction?) and race abilities, can probably just add those skills to the trait table on char creation. Also how would the level be determined for the list? For traits the spell could just be set to the level of the choice but what about class training with spells of various levels?

The more I think about it I keep ending up with almost the same table I had before so advice is welcome.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Character Traits

Post by John Adams » Fri Oct 21, 2011 4:12 pm

Adding a single column to `spells` for these is no big deal, but if it does become more non-spell-like data, then sure, we could add a child table off spells.

Zcoretri might correct me, but I believe "Who can use a spell" is determined by the skill_req data in the spells table itself. So that would take care of what race is allowed to use what spell.

Level is set in spell_classes, which (currently) holds the adventure, tradeskill class_id's, plus the level for each.

Spells, in general, are on my design table for a re-vamp, due to the newer (SF) spell names, we have to rethink our data for spells... but don't let that get in your way. It'll be some time before I get to that system again.

Jabantiz
Lead Developer
Posts: 2912
Joined: Wed Jul 25, 2007 2:52 pm
Location: California

Re: Character Traits

Post by Jabantiz » Fri Oct 28, 2011 12:30 pm

I was hoping to have the basic system done by this weekend but I have ran into a problem constructing the packets. The client expects 5 traits to be sent per line, in the event there is only 4 traits on that line then the 5th would be all 0xFF and the name field would not be sent at all. I constructed the packet with

Code: Select all

packet->setArrayDataByName(name, data);
Not calling that function for trait_name (EQ16BitString) still puts the string size into the packet (0x00 0x00) causing the client to crash. Is there a way to prevent that from being added to the packet that I am missing?

User avatar
Zcoretri
Team Member
Posts: 1642
Joined: Fri Jul 27, 2007 12:55 pm
Location: SoCal

Re: Character Traits

Post by Zcoretri » Fri Oct 28, 2011 3:57 pm

Scat should probably weigh in on this, but what you could do is check for no data.
If there is no data, send the FF's

Code: Select all

if (data == null)
     packet->setArrayDataByName("trait4_icon", 0xFFFF);
     packet->setArrayDataByName("trait4_id", 0xFFFFFFFF);
     ....
else
     packet->setArrayDataByName("trait4_id", data);
     packet->setArrayDataByName("trait4_icon", data);
     .....

Jabantiz
Lead Developer
Posts: 2912
Joined: Wed Jul 25, 2007 2:52 pm
Location: California

Re: Character Traits

Post by Jabantiz » Fri Oct 28, 2011 4:30 pm

That is what I currently do in setting up the packet, however when this needs to happen the trait_name is not sent at all. trait_name is of type EQ216BitString and no matter how it is set(don't set it at all or set it to "") the size of the string is put into the packet, in this case 00 00, wich then makes the data to long.

Also I was wrong on it causing the client to crash, I forgot to put the size of the packet at the begining, trying to figure out how to do that but no luck so far.

User avatar
Zcoretri
Team Member
Posts: 1642
Joined: Fri Jul 27, 2007 12:55 pm
Location: SoCal

Re: Character Traits

Post by Zcoretri » Fri Oct 28, 2011 6:27 pm

What do you mean size of packet?
Are you using my WS_TraitsList struct from the WorldStructs.xml file? If not, post yours please.

I was planning on implementing this myself, until you popped up and dived in.

Jabantiz
Lead Developer
Posts: 2912
Joined: Wed Jul 25, 2007 2:52 pm
Location: California

Re: Character Traits

Post by Jabantiz » Fri Oct 28, 2011 7:11 pm

yes I am using WS_TraitsList and get that filled out correctly and the packet looks good, except for the extra 00 I mentioned, but at the very start of the packet you need to add the size of the packet in 4 bytes. Looking through the code every packet that adds the size seems to do it diffrently with static numbers that seem specific to the packet but no idea what they represent.

EDIT:

For example, in Spell::SerializeSpell at the end is the following code wich adds the size of the packet to the begining of the packet before it is sent.

Code: Select all

string* data1 = packet->serializeString();
uchar*  data2 = (uchar*)data1->c_str();
uchar*  ptr2 = data2;
int32 size = data1->length() * 2;
uchar* data3 = new uchar[size];
memcpy(data3, data2, data1->length());
uchar* ptr = data3;
size -=17;
memcpy(ptr, &size, sizeof(int32)); 
size +=3;
ptr += data1->length();
ptr2 += 14;
memcpy(ptr, ptr2, data1->length() - 14);

EQ2Packet* outapp = new EQ2Packet(OP_ClientCmdMsg, data3, size);
I do not understand where those static numbers come from. Another example is in client::loot() but the variable used is modified through out half of that function and again with static values.

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Re: Character Traits

Post by Scatman » Sat Oct 29, 2011 11:35 am

Try using the IfVariableSet XML property.
<Data ElementName="unknown4" Type="int32" IfVariableSet="stack_0" />

So I think (not 100% sure), what that does is, not use unknown4 if stack_0 is set. There is also a IfVariableNotSet property as well if that suits you better.

Jabantiz
Lead Developer
Posts: 2912
Joined: Wed Jul 25, 2007 2:52 pm
Location: California

Re: Character Traits

Post by Jabantiz » Sat Oct 29, 2011 4:16 pm

With the help of Zcoretri last night we figured out my problem was the struct, after he showed me how to fix it every thing started working great. I am attaching a .rar with the files and a patch to show my current progress, wich isn't to much just populates the list. I only created 1 table, spell_traits

Code: Select all

CREATE TABLE `spell_traits` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`spell_id` INT(10) UNSIGNED NOT NULL DEFAULT '0',
	`level` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
	`class_req` TINYINT(3) UNSIGNED NOT NULL DEFAULT '255',
	`race_req` TINYINT(3) UNSIGNED NOT NULL DEFAULT '255',
	`isInate` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
	PRIMARY KEY (`id`),
	INDEX `FK_spell_traits` (`spell_id`),
	CONSTRAINT `FK_spell_traits` FOREIGN KEY (`spell_id`) REFERENCES `spells` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='latin1_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=1
Here is the data I used to test this

Code: Select all

INSERT INTO `spells` (`id`, `type`, `cast_type`, `name`, `description`, `icon`, `icon2`, `icontype`, `class_skill`, `mastery_skill`, `min_class_skill_req`, `duration_until_cancel`, `target_type`, `success_message`, `fade_message`, `interruptable`, `lua_script`, `spell_visual`, `effect_message`, `spell_book_type`, `can_effect_raid`, `affect_only_group_members`, `display_spell_tier`, `friendly_spell`, `group_spell`, `is_active`) VALUES (1000000, 1, 0, 'Brawny', 'Increace Str', 89, 65535, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `spells` (`id`, `type`, `cast_type`, `name`, `description`, `icon`, `icon2`, `icontype`, `class_skill`, `mastery_skill`, `min_class_skill_req`, `duration_until_cancel`, `target_type`, `success_message`, `fade_message`, `interruptable`, `lua_script`, `spell_visual`, `effect_message`, `spell_book_type`, `can_effect_raid`, `affect_only_group_members`, `display_spell_tier`, `friendly_spell`, `group_spell`, `is_active`) VALUES (1000001, 1, 0, 'Nimble', 'Increace Agi', 90, 65535, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `spells` (`id`, `type`, `cast_type`, `name`, `description`, `icon`, `icon2`, `icontype`, `class_skill`, `mastery_skill`, `min_class_skill_req`, `duration_until_cancel`, `target_type`, `success_message`, `fade_message`, `interruptable`, `lua_script`, `spell_visual`, `effect_message`, `spell_book_type`, `can_effect_raid`, `affect_only_group_members`, `display_spell_tier`, `friendly_spell`, `group_spell`, `is_active`) VALUES (1000002, 1, 0, 'Muscular', 'Increace Sta', 89, 65535, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `spells` (`id`, `type`, `cast_type`, `name`, `description`, `icon`, `icon2`, `icontype`, `class_skill`, `mastery_skill`, `min_class_skill_req`, `duration_until_cancel`, `target_type`, `success_message`, `fade_message`, `interruptable`, `lua_script`, `spell_visual`, `effect_message`, `spell_book_type`, `can_effect_raid`, `affect_only_group_members`, `display_spell_tier`, `friendly_spell`, `group_spell`, `is_active`) VALUES (1000003, 1, 0, 'Hardy', 'Increace Physical Resist', 147, 65535, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0, NULL, 0, 0, 0, 0, 0, 0, 0);

Code: Select all

INSERT INTO `spell_classes` (`id`, `spell_id`, `adventure_class_id`, `tradeskill_class_id`, `level`) VALUES (40798, 1000000, 255, 255, 8);
INSERT INTO `spell_classes` (`id`, `spell_id`, `adventure_class_id`, `tradeskill_class_id`, `level`) VALUES (40799, 1000001, 255, 255, 8);
INSERT INTO `spell_classes` (`id`, `spell_id`, `adventure_class_id`, `tradeskill_class_id`, `level`) VALUES (40800, 1000002, 255, 255, 28);
INSERT INTO `spell_classes` (`id`, `spell_id`, `adventure_class_id`, `tradeskill_class_id`, `level`) VALUES (40801, 1000003, 255, 255, 15);

Code: Select all

INSERT INTO `spell_data` (`id`, `spell_id`, `tier`, `index_field`, `value_type`, `value`, `value2`) VALUES (1263, 1000000, 0, 0, 'INT', '5', '0');
INSERT INTO `spell_data` (`id`, `spell_id`, `tier`, `index_field`, `value_type`, `value`, `value2`) VALUES (1264, 1000001, 0, 0, 'INT', '5', '0');
INSERT INTO `spell_data` (`id`, `spell_id`, `tier`, `index_field`, `value_type`, `value`, `value2`) VALUES (1265, 1000002, 0, 0, 'INT', '5', '0');
INSERT INTO `spell_data` (`id`, `spell_id`, `tier`, `index_field`, `value_type`, `value`, `value2`) VALUES (1266, 1000003, 0, 0, 'INT', '5', '0');

Code: Select all

INSERT INTO `spell_display_effects` (`id`, `spell_id`, `tier`, `percentage`, `description`, `bullet`, `index`) VALUES (1683, 1000000, 0, 100, 'Increases Str', 0, 0);
INSERT INTO `spell_display_effects` (`id`, `spell_id`, `tier`, `percentage`, `description`, `bullet`, `index`) VALUES (1684, 1000001, 0, 100, 'Increases Agi', 0, 0);
INSERT INTO `spell_display_effects` (`id`, `spell_id`, `tier`, `percentage`, `description`, `bullet`, `index`) VALUES (1685, 1000002, 0, 100, 'Increases Str', 0, 0);
INSERT INTO `spell_display_effects` (`id`, `spell_id`, `tier`, `percentage`, `description`, `bullet`, `index`) VALUES (1686, 1000003, 0, 100, 'Increases Physical Resist', 0, 0);

Code: Select all

INSERT INTO `spell_tiers` (`id`, `spell_id`, `tier`, `hp_req`, `hp_req_percent`, `hp_upkeep`, `power_req`, `power_req_percent`, `power_upkeep`, `req_concentration`, `cast_time`, `recovery`, `recast`, `radius`, `max_aoe_targets`, `min_range`, `range`, `duration1`, `duration2`, `resistibility`, `hit_bonus`, `call_frequency`, `unknown9`) VALUES (8827, 1000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `spell_tiers` (`id`, `spell_id`, `tier`, `hp_req`, `hp_req_percent`, `hp_upkeep`, `power_req`, `power_req_percent`, `power_upkeep`, `req_concentration`, `cast_time`, `recovery`, `recast`, `radius`, `max_aoe_targets`, `min_range`, `range`, `duration1`, `duration2`, `resistibility`, `hit_bonus`, `call_frequency`, `unknown9`) VALUES (8828, 1000001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `spell_tiers` (`id`, `spell_id`, `tier`, `hp_req`, `hp_req_percent`, `hp_upkeep`, `power_req`, `power_req_percent`, `power_upkeep`, `req_concentration`, `cast_time`, `recovery`, `recast`, `radius`, `max_aoe_targets`, `min_range`, `range`, `duration1`, `duration2`, `resistibility`, `hit_bonus`, `call_frequency`, `unknown9`) VALUES (8829, 1000002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `spell_tiers` (`id`, `spell_id`, `tier`, `hp_req`, `hp_req_percent`, `hp_upkeep`, `power_req`, `power_req_percent`, `power_upkeep`, `req_concentration`, `cast_time`, `recovery`, `recast`, `radius`, `max_aoe_targets`, `min_range`, `range`, `duration1`, `duration2`, `resistibility`, `hit_bonus`, `call_frequency`, `unknown9`) VALUES (8830, 1000003, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

Code: Select all

INSERT INTO `spell_traits` (`id`, `spell_id`, `level`, `class_req`, `race_req`, `isInate`) VALUES (1, 1000000, 8, 255, 255, 0);
INSERT INTO `spell_traits` (`id`, `spell_id`, `level`, `class_req`, `race_req`, `isInate`) VALUES (2, 1000001, 8, 255, 255, 0);
INSERT INTO `spell_traits` (`id`, `spell_id`, `level`, `class_req`, `race_req`, `isInate`) VALUES (3, 1000002, 28, 255, 255, 0);
INSERT INTO `spell_traits` (`id`, `spell_id`, `level`, `class_req`, `race_req`, `isInate`) VALUES (4, 1000003, 15, 255, 255, 0);
This is the most complicated thing I have done with programming in a long time so please comment and let me know what I can improve. (This only populates the list right now)
You do not have the required permissions to view the files attached to this post.

User avatar
Zcoretri
Team Member
Posts: 1642
Joined: Fri Jul 27, 2007 12:55 pm
Location: SoCal

Re: Character Traits

Post by Zcoretri » Sun Oct 30, 2011 5:17 pm

With Jabantiz's great contribution to some emu C++ code, we have the beginnings to character traits...
char_traits.png
oh and yeah...with xinux's tirelessly fooling with the character sheet struct, we have identified some unknowns.
As you can see above, I located some unknowns for AA stuff :mrgreen:

Thanks to both Jabantiz and xinux for thier contributions :!:
You do not have the required permissions to view the files attached to this post.

Jabantiz
Lead Developer
Posts: 2912
Joined: Wed Jul 25, 2007 2:52 pm
Location: California

Re: Character Traits

Post by Jabantiz » Sun Oct 30, 2011 6:03 pm

Attaching a new .rar with update I made today. Mainly took out all the notes I had put into the files as well as some useless LogWrite calls. This will allow a player to select a trait now and update the list / save it.

Required sql

Code: Select all

UPDATE `commands` SET `handler`=293 WHERE `command` = "accept_advancement";
Also the traits should have there entry in the spells table updated to set spell_book_type = 4 so they do not appear in the spell book.

The patch was made off of the current public svn.
You do not have the required permissions to view the files attached to this post.

User avatar
Zcoretri
Team Member
Posts: 1642
Joined: Fri Jul 27, 2007 12:55 pm
Location: SoCal

Re: Character Traits

Post by Zcoretri » Sun Oct 30, 2011 6:12 pm

Jabantiz wrote:Attaching a new .rar with update I made today. Mainly took out all the notes I had put into the files as well as some useless LogWrite calls. This will allow a player to select a trait now and update the list / save it.

Required sql

Code: Select all

UPDATE `commands` SET `handler`=293 WHERE `command` = "accept_advancement";
Also the traits should have there entry in the spells table updated to set spell_book_type = 4 so they do not appear in the spell book.

The patch was made off of the current public svn.

Cool, I will add this in also...thanks Jabantiz :)

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Re: Character Traits

Post by John Adams » Mon Oct 31, 2011 8:27 am

You guys are kicking ass! Thank you for getting involved. This is a very good sign ;)

Now if I can just get you to commit your efforts to SVN, we'll be golden. No sense duplicating the effort, you both (all) have write access. Don't worry if something is wrong, or buggy. It's SVN. We can always revert ;)


As for DB/table modifications, you can continue to post your tables for now since my DB update scripts (on the portal) seem to re-write themselves day to day and break. Not sure what's up there.

Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests