Browse Source

Support for attack_type and other combat parameters in the infostruct, Fix #415

Emagi 1 year ago
parent
commit
1209657776

+ 25 - 0
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -196,6 +196,7 @@ Commands::Commands(){
 	spawn_set_values["soga_nose_type"] = SPAWN_SET_SOGA_NOSE_TYPE;
 	spawn_set_values["soga_body_size"] = SPAWN_SET_SOGA_BODY_SIZE;
 	spawn_set_values["soga_body_age"] = SPAWN_SET_SOGA_BODY_AGE;
+	spawn_set_values["attack_type"] = SPAWN_SET_ATTACK_TYPE;
 
 	zone_set_values["expansion_id"] = ZONE_SET_VALUE_EXPANSION_ID;
 	zone_set_values["name"] = ZONE_SET_VALUE_NAME;
@@ -845,6 +846,14 @@ bool Commands::SetSpawnCommand(Client* client, Spawn* target, int8 type, const c
 				}
 				break;
 			}
+			case SPAWN_SET_ATTACK_TYPE:{
+				if(target->IsEntity()){
+					sprintf(tmp, "%u", ((Entity*)target)->GetInfoStruct()->get_attack_type());
+					int8 new_value = atoul(value);
+					((Entity*)target)->GetInfoStruct()->set_attack_type(new_value);
+				}
+				break;
+			}
 
 			if(temp_value)
 				*temp_value = string(tmp);
@@ -1480,6 +1489,21 @@ bool Commands::SetSpawnCommand(Client* client, Spawn* target, int8 type, const c
 				}
 				break;
 			}
+			case SPAWN_SET_ATTACK_TYPE:{
+				if(target->IsEntity()){
+					int8 new_value = atoul(value);
+					((Entity*)target)->GetInfoStruct()->set_attack_type(new_value);
+					if(target->IsNPC()) {
+						if(target->GetDatabaseID()) {
+							Query spawnNPCQuery;					
+							spawnNPCQuery.AddQueryAsync(0, &database, Q_INSERT, "update spawn_npc set attack_type=%u where id=%u", new_value, target->GetDatabaseID());
+						} else if(client) {
+							client->Message(CHANNEL_COLOR_RED, "Invalid spawn to update the database (NPC only) or no database id for the NPC present.");
+						}
+					}
+				}
+				break;
+			}
 		}
 	}
 	return true;
@@ -4789,6 +4813,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 								case SPAWN_SET_SOGA_NOSE_TYPE:
 								case SPAWN_SET_SOGA_BODY_SIZE:
 								case SPAWN_SET_SOGA_BODY_AGE:
+								case SPAWN_SET_ATTACK_TYPE:
 								{
 									// not applicable already ran db command
 									break;

+ 2 - 0
EQ2/source/WorldServer/Commands/Commands.h

@@ -565,6 +565,8 @@ private:
 #define SPAWN_SET_SOGA_BODY_SIZE						100
 #define SPAWN_SET_SOGA_BODY_AGE							101
 
+#define SPAWN_SET_ATTACK_TYPE							102
+
 #define ZONE_SET_VALUE_EXPANSION_ID			0
 #define ZONE_SET_VALUE_NAME					1
 #define ZONE_SET_VALUE_FILE					2

+ 163 - 57
EQ2/source/WorldServer/Entity.cpp

@@ -52,8 +52,6 @@ Entity::Entity(){
 	regen_power_rate = 0;
 	in_combat = false;
 	casting = false;
-	memset(&melee_combat_data, 0, sizeof(CombatData));
-	memset(&ranged_combat_data, 0, sizeof(CombatData));
 	//memset(&info_struct, 0, sizeof(InfoStruct));
 	memset(&features, 0, sizeof(CharFeatures));
 	memset(&equipment, 0, sizeof(EQ2_Equipment));
@@ -304,6 +302,36 @@ void Entity::MapInfoStruct()
 	get_int8_funcs["interaction_flag"] = l::bind(&InfoStruct::get_interaction_flag, &info_struct);
 	get_int8_funcs["tag1"] = l::bind(&InfoStruct::get_tag1, &info_struct);
 	get_int16_funcs["mood"] = l::bind(&InfoStruct::get_mood, &info_struct);
+	
+	get_int32_funcs["range_last_attack_time"] = l::bind(&InfoStruct::get_range_last_attack_time, &info_struct);
+	get_int32_funcs["primary_last_attack_time"] = l::bind(&InfoStruct::get_primary_last_attack_time, &info_struct);
+	get_int32_funcs["secondary_last_attack_time"] = l::bind(&InfoStruct::get_secondary_last_attack_time, &info_struct);
+	
+	get_int16_funcs["primary_attack_delay"] = l::bind(&InfoStruct::get_primary_attack_delay, &info_struct);
+	get_int16_funcs["secondary_attack_delay"] = l::bind(&InfoStruct::get_secondary_attack_delay, &info_struct);
+	get_int16_funcs["ranged_attack_delay"] = l::bind(&InfoStruct::get_ranged_attack_delay, &info_struct);
+	
+	get_int8_funcs["primary_weapon_type"] = l::bind(&InfoStruct::get_primary_weapon_type, &info_struct);
+	get_int8_funcs["secondary_weapon_type"] = l::bind(&InfoStruct::get_secondary_weapon_type, &info_struct);
+	get_int8_funcs["ranged_weapon_type"] = l::bind(&InfoStruct::get_ranged_weapon_type, &info_struct);
+	
+	get_int32_funcs["primary_weapon_damage_low"] = l::bind(&InfoStruct::get_primary_weapon_damage_low, &info_struct);
+	get_int32_funcs["primary_weapon_damage_high"] = l::bind(&InfoStruct::get_primary_weapon_damage_high, &info_struct);
+	get_int32_funcs["secondary_weapon_damage_low"] = l::bind(&InfoStruct::get_secondary_weapon_damage_low, &info_struct);
+	get_int32_funcs["secondary_weapon_damage_high"] = l::bind(&InfoStruct::get_secondary_weapon_damage_high, &info_struct);
+	get_int32_funcs["ranged_weapon_damage_low"] = l::bind(&InfoStruct::get_ranged_weapon_damage_low, &info_struct);
+	get_int32_funcs["ranged_weapon_damage_high"] = l::bind(&InfoStruct::get_ranged_weapon_damage_high, &info_struct);
+	
+	get_int8_funcs["wield_type"] = l::bind(&InfoStruct::get_wield_type, &info_struct);
+	get_int8_funcs["attack_type"] = l::bind(&InfoStruct::get_attack_type, &info_struct);
+	
+	get_int16_funcs["primary_weapon_delay"] = l::bind(&InfoStruct::get_primary_weapon_delay, &info_struct);
+	get_int16_funcs["secondary_weapon_delay"] = l::bind(&InfoStruct::get_secondary_weapon_delay, &info_struct);
+	get_int16_funcs["ranged_weapon_delay"] = l::bind(&InfoStruct::get_ranged_weapon_delay, &info_struct);
+	
+	get_int8_funcs["override_primary_weapon"] = l::bind(&InfoStruct::get_override_primary_weapon, &info_struct);
+	get_int8_funcs["override_secondary_weapon"] = l::bind(&InfoStruct::get_override_secondary_weapon, &info_struct);
+	get_int8_funcs["override_ranged_weapon"] = l::bind(&InfoStruct::get_override_ranged_weapon, &info_struct);
 
 /** SETS **/
 	set_string_funcs["name"] = l::bind(&InfoStruct::set_name, &info_struct, l::_1);
@@ -453,6 +481,35 @@ void Entity::MapInfoStruct()
 	set_int8_funcs["tag1"] = l::bind(&InfoStruct::set_tag1, &info_struct, l::_1);
 	set_int16_funcs["mood"] = l::bind(&InfoStruct::set_mood, &info_struct, l::_1);
 
+	set_int32_funcs["range_last_attack_time"] = l::bind(&InfoStruct::set_range_last_attack_time, &info_struct, l::_1);
+	set_int32_funcs["primary_last_attack_time"] = l::bind(&InfoStruct::set_primary_last_attack_time, &info_struct, l::_1);
+	set_int32_funcs["secondary_last_attack_time"] = l::bind(&InfoStruct::set_secondary_last_attack_time, &info_struct, l::_1);
+	
+	set_int16_funcs["primary_attack_delay"] = l::bind(&InfoStruct::set_primary_attack_delay, &info_struct, l::_1);
+	set_int16_funcs["secondary_attack_delay"] = l::bind(&InfoStruct::set_secondary_attack_delay, &info_struct, l::_1);
+	set_int16_funcs["ranged_attack_delay"] = l::bind(&InfoStruct::set_ranged_attack_delay, &info_struct, l::_1);
+	
+	set_int8_funcs["primary_weapon_type"] = l::bind(&InfoStruct::set_primary_weapon_type, &info_struct, l::_1);
+	set_int8_funcs["secondary_weapon_type"] = l::bind(&InfoStruct::set_secondary_weapon_type, &info_struct, l::_1);
+	set_int8_funcs["ranged_weapon_type"] = l::bind(&InfoStruct::set_ranged_weapon_type, &info_struct, l::_1);
+	
+	set_int32_funcs["primary_weapon_damage_low"] = l::bind(&InfoStruct::set_primary_weapon_damage_low, &info_struct, l::_1);
+	set_int32_funcs["primary_weapon_damage_high"] = l::bind(&InfoStruct::set_primary_weapon_damage_high, &info_struct, l::_1);
+	set_int32_funcs["secondary_weapon_damage_low"] = l::bind(&InfoStruct::set_secondary_weapon_damage_low, &info_struct, l::_1);
+	set_int32_funcs["secondary_weapon_damage_high"] = l::bind(&InfoStruct::set_secondary_weapon_damage_high, &info_struct, l::_1);
+	set_int32_funcs["ranged_weapon_damage_low"] = l::bind(&InfoStruct::set_ranged_weapon_damage_low, &info_struct, l::_1);
+	set_int32_funcs["ranged_weapon_damage_high"] = l::bind(&InfoStruct::set_ranged_weapon_damage_high, &info_struct, l::_1);
+	
+	set_int8_funcs["wield_type"] = l::bind(&InfoStruct::set_wield_type, &info_struct, l::_1);
+	set_int8_funcs["attack_type"] = l::bind(&InfoStruct::set_attack_type, &info_struct, l::_1);
+	
+	set_int16_funcs["primary_weapon_delay"] = l::bind(&InfoStruct::set_primary_weapon_delay, &info_struct, l::_1);
+	set_int16_funcs["secondary_weapon_delay"] = l::bind(&InfoStruct::set_secondary_weapon_delay, &info_struct, l::_1);
+	set_int16_funcs["ranged_weapon_delay"] = l::bind(&InfoStruct::set_ranged_weapon_delay, &info_struct, l::_1);
+	
+	set_int8_funcs["override_primary_weapon"] = l::bind(&InfoStruct::set_override_primary_weapon, &info_struct, l::_1);
+	set_int8_funcs["override_secondary_weapon"] = l::bind(&InfoStruct::set_override_secondary_weapon, &info_struct, l::_1);
+	set_int8_funcs["override_ranged_weapon"] = l::bind(&InfoStruct::set_override_ranged_weapon, &info_struct, l::_1);
 }
 
 bool Entity::HasMoved(bool include_heading){
@@ -598,15 +655,15 @@ void Entity::IsCasting(bool val){
 }
 
 int32 Entity::GetRangeLastAttackTime(){
-	return ranged_combat_data.range_last_attack_time;
+	return GetInfoStruct()->get_range_last_attack_time();
 }
 
 void Entity::SetRangeLastAttackTime(int32 time){
-	ranged_combat_data.range_last_attack_time = time;
+	GetInfoStruct()->set_range_last_attack_time(time);
 }
 
 int16 Entity::GetRangeAttackDelay(){
-	return ranged_combat_data.ranged_attack_delay;
+	return GetInfoStruct()->get_ranged_attack_delay();
 //	if(IsPlayer()){
 //		Item* item = ((Player*)this)->GetEquipmentList()->GetItem(EQ2_RANGE_SLOT);
 //		if(item && item->IsRanged())
@@ -616,142 +673,191 @@ int16 Entity::GetRangeAttackDelay(){
 }
 
 int32 Entity::GetPrimaryLastAttackTime(){
-	return melee_combat_data.primary_last_attack_time;
+	return GetInfoStruct()->get_primary_last_attack_time();
 }
 
 int16 Entity::GetPrimaryAttackDelay(){
-	return melee_combat_data.primary_attack_delay;
+	return GetInfoStruct()->get_primary_attack_delay();
 }
 
 void Entity::SetPrimaryAttackDelay(int16 new_delay){
-	melee_combat_data.primary_attack_delay = new_delay;
+	GetInfoStruct()->set_primary_attack_delay(new_delay);
 }
 
 void Entity::SetPrimaryLastAttackTime(int32 new_time){
-	melee_combat_data.primary_last_attack_time = new_time;
+	GetInfoStruct()->set_primary_last_attack_time(new_time);
 }
 
 int32 Entity::GetSecondaryLastAttackTime(){
-	return melee_combat_data.secondary_last_attack_time;
+	return GetInfoStruct()->get_secondary_last_attack_time();
 }
 
 int16 Entity::GetSecondaryAttackDelay(){
-	return melee_combat_data.secondary_attack_delay;
+	return GetInfoStruct()->get_secondary_attack_delay();
 }
 
 void Entity::SetSecondaryAttackDelay(int16 new_delay){
-	melee_combat_data.secondary_attack_delay = new_delay;
+	GetInfoStruct()->set_secondary_attack_delay(new_delay);
 }
 
 void Entity::SetSecondaryLastAttackTime(int32 new_time){
-	melee_combat_data.secondary_last_attack_time = new_time;
+	GetInfoStruct()->set_secondary_last_attack_time(new_time);
 }
 
 void Entity::ChangePrimaryWeapon(){
+	if(GetInfoStruct()->get_override_primary_weapon()) {
+		return;
+	}
+	
 	Item* item = equipment_list.GetItem(EQ2_PRIMARY_SLOT);
 	if(item && item->details.item_id > 0 && item->IsWeapon()){
-		melee_combat_data.primary_weapon_delay = item->weapon_info->delay * 100;
-		melee_combat_data.primary_weapon_damage_low = item->weapon_info->damage_low3;
-		melee_combat_data.primary_weapon_damage_high = item->weapon_info->damage_high3;
-		melee_combat_data.primary_weapon_type = item->GetWeaponType();
-		melee_combat_data.wield_type = item->weapon_info->wield_type;
+		GetInfoStruct()->set_primary_weapon_delay(item->weapon_info->delay * 100);
+		GetInfoStruct()->set_primary_weapon_damage_low(item->weapon_info->damage_low3);
+		GetInfoStruct()->set_primary_weapon_damage_high(item->weapon_info->damage_high3);
+		GetInfoStruct()->set_primary_weapon_type(item->GetWeaponType());
+		GetInfoStruct()->set_wield_type(item->weapon_info->wield_type);
 	}
 	else{
 		int16 effective_level = GetInfoStruct()->get_effective_level();
 		if ( !effective_level )
 			effective_level = GetLevel();
 
-		melee_combat_data.primary_weapon_delay = 2000;
-		melee_combat_data.primary_weapon_damage_low = (int32)(1 + effective_level * .2);
-		melee_combat_data.primary_weapon_damage_high = (int32)(5 + effective_level * (effective_level/5));
-		if(IsNPC())
-			melee_combat_data.primary_weapon_type = ((NPC*)this)->GetAttackType();
-		else
-			melee_combat_data.primary_weapon_type = 1;
-		melee_combat_data.wield_type = 2;
+			GetInfoStruct()->set_primary_weapon_delay(2000);		
+			GetInfoStruct()->set_primary_weapon_damage_low((int32)1 + effective_level * .2);
+			GetInfoStruct()->set_primary_weapon_damage_high((int32)(5 + effective_level * (effective_level/5)));
+			if(GetInfoStruct()->get_attack_type() > 0) {
+				GetInfoStruct()->set_primary_weapon_type(GetInfoStruct()->get_attack_type());
+			}
+			else {
+				GetInfoStruct()->set_primary_weapon_type(1);
+			}
+			GetInfoStruct()->set_wield_type(2);
+	}
+	
+	int32 weapon_dmg_high = GetInfoStruct()->get_primary_weapon_damage_high();
+	if(IsNPC()) {
+		GetInfoStruct()->set_primary_weapon_damage_high(weapon_dmg_high + (int32)((GetInfoStruct()->get_str() / 10)));
+	}
+	else { 
+		GetInfoStruct()->set_primary_weapon_damage_high(weapon_dmg_high + (int32)((GetInfoStruct()->get_str() / 25)));
 	}
-	if(IsNPC())
-		melee_combat_data.primary_weapon_damage_high += (int32)(GetInfoStruct()->get_str() / 10);
-	else
-		melee_combat_data.primary_weapon_damage_high += (int32)(GetInfoStruct()->get_str() / 25);
 }
 
 void Entity::ChangeSecondaryWeapon(){
+	if(GetInfoStruct()->get_override_secondary_weapon()) {
+		return;
+	}
+	
 	Item* item = equipment_list.GetItem(EQ2_SECONDARY_SLOT);
 	if(item && item->details.item_id > 0 && item->IsWeapon()){
-		melee_combat_data.secondary_weapon_delay = item->weapon_info->delay * 100;
-		melee_combat_data.secondary_weapon_damage_low = item->weapon_info->damage_low3;
-		melee_combat_data.secondary_weapon_damage_high = item->weapon_info->damage_high3;
-		melee_combat_data.secondary_weapon_type = item->GetWeaponType();
+		GetInfoStruct()->set_secondary_weapon_delay(item->weapon_info->delay * 100);
+		GetInfoStruct()->set_secondary_weapon_damage_low(item->weapon_info->damage_low3);
+		GetInfoStruct()->set_secondary_weapon_damage_high(item->weapon_info->damage_high3);
+		GetInfoStruct()->set_secondary_weapon_type(item->GetWeaponType());
 	}
 	else{
 		int16 effective_level = GetInfoStruct()->get_effective_level();
 		if ( !effective_level )
 			effective_level = GetLevel();
 
-		melee_combat_data.secondary_weapon_delay = 2000;
-		melee_combat_data.secondary_weapon_damage_low = (int32)(1 + effective_level * .2);
-		melee_combat_data.secondary_weapon_damage_high = (int32)(5 + effective_level * (effective_level/6));
-		melee_combat_data.secondary_weapon_type = 1;
+		GetInfoStruct()->set_secondary_weapon_delay(2000);
+		GetInfoStruct()->set_secondary_weapon_damage_low((int32)(1 + effective_level * .2));
+		GetInfoStruct()->set_secondary_weapon_damage_high((int32)(5 + effective_level * (effective_level/6)));
+		GetInfoStruct()->set_secondary_weapon_type(1);
+	}
+	
+	int32 weapon_dmg_high = GetInfoStruct()->get_secondary_weapon_damage_high();
+	if(IsNPC()) {
+		GetInfoStruct()->set_secondary_weapon_damage_high(weapon_dmg_high + (int32)((GetInfoStruct()->get_str() / 10)));
+	}
+	else {
+		GetInfoStruct()->set_secondary_weapon_damage_high(weapon_dmg_high + (int32)((GetInfoStruct()->get_str() / 25)));
 	}
-	if(IsNPC())
-		melee_combat_data.secondary_weapon_damage_high += (int32)(GetInfoStruct()->get_str() / 10);
-	else
-		melee_combat_data.secondary_weapon_damage_high += (int32)(GetInfoStruct()->get_str() / 25);
 }
 
 void Entity::ChangeRangedWeapon(){
+	if(GetInfoStruct()->get_override_ranged_weapon()) {
+		return;
+	}
+	
 	Item* item = equipment_list.GetItem(EQ2_RANGE_SLOT);
 	if(item && item->details.item_id > 0 && item->IsRanged()){
-		ranged_combat_data.ranged_weapon_delay = item->ranged_info->weapon_info.delay*100;
-		ranged_combat_data.ranged_weapon_damage_low = item->ranged_info->weapon_info.damage_low3;
-		ranged_combat_data.ranged_weapon_damage_high = item->ranged_info->weapon_info.damage_high3;
-		ranged_combat_data.ranged_weapon_type = item->GetWeaponType();
+		GetInfoStruct()->set_ranged_weapon_delay(item->ranged_info->weapon_info.delay*100);
+		GetInfoStruct()->set_ranged_weapon_damage_low(item->ranged_info->weapon_info.damage_low3);
+		GetInfoStruct()->set_ranged_weapon_damage_high(item->ranged_info->weapon_info.damage_high3);
+		GetInfoStruct()->set_ranged_weapon_type(item->GetWeaponType());
 	}
 }
 
 int32 Entity::GetPrimaryWeaponMinDamage(){
-	return melee_combat_data.primary_weapon_damage_low;
+	return GetInfoStruct()->get_primary_weapon_damage_low();
 }
 
 int32 Entity::GetPrimaryWeaponMaxDamage(){
-	return melee_combat_data.primary_weapon_damage_high;
+	return GetInfoStruct()->get_primary_weapon_damage_high();
+}
+
+int16 Entity::GetPrimaryWeaponDelay(){
+	return GetInfoStruct()->get_primary_weapon_delay();
+}
+
+int16 Entity::GetSecondaryWeaponDelay(){
+	return GetInfoStruct()->get_secondary_weapon_delay();
 }
 
 int32 Entity::GetSecondaryWeaponMinDamage(){
-	return melee_combat_data.secondary_weapon_damage_low;
+	return GetInfoStruct()->get_secondary_weapon_damage_low();
 }
 
 int32 Entity::GetSecondaryWeaponMaxDamage(){
-	return melee_combat_data.secondary_weapon_damage_high;
+	return GetInfoStruct()->get_secondary_weapon_damage_high();
 }
 
 int8 Entity::GetPrimaryWeaponType(){
-	return melee_combat_data.primary_weapon_type;
+	return GetInfoStruct()->get_primary_weapon_type();
 }
 
 int8 Entity::GetSecondaryWeaponType(){
-	return melee_combat_data.secondary_weapon_type;
+	return GetInfoStruct()->get_secondary_weapon_type();
 }
 
 int32 Entity::GetRangedWeaponMinDamage(){
-	return ranged_combat_data.ranged_weapon_damage_low;
+	return GetInfoStruct()->get_ranged_weapon_damage_low();
 }
 
 int32 Entity::GetRangedWeaponMaxDamage(){
-	return ranged_combat_data.ranged_weapon_damage_high;
+	return GetInfoStruct()->get_ranged_weapon_damage_high();
 }
 
 int8 Entity::GetRangedWeaponType(){
-	return ranged_combat_data.ranged_weapon_type;
+	return GetInfoStruct()->get_ranged_weapon_type();
 }
 
 bool Entity::IsDualWield(){
-	return melee_combat_data.wield_type == 1;
+	return GetInfoStruct()->get_wield_type() == 1;
 }
 
 int8 Entity::GetWieldType(){
-	return melee_combat_data.wield_type;
+	return GetInfoStruct()->get_wield_type();
+}
+
+int16 Entity::GetRangeWeaponDelay(){
+	return GetInfoStruct()->get_ranged_weapon_delay();
+}
+
+void Entity::SetRangeWeaponDelay(int16 new_delay){
+	GetInfoStruct()->set_ranged_weapon_delay(new_delay * 100);
+}
+void Entity::SetRangeAttackDelay(int16 new_delay){
+	GetInfoStruct()->set_ranged_attack_delay(new_delay);
+}
+
+void Entity::SetPrimaryWeaponDelay(int16 new_delay){
+	GetInfoStruct()->set_primary_weapon_delay(new_delay * 100);
+}
+
+void Entity::SetSecondaryWeaponDelay(int16 new_delay){
+	GetInfoStruct()->set_primary_weapon_delay(new_delay * 100);
 }
 
 bool Entity::BehindTarget(Spawn* target){

+ 143 - 31
EQ2/source/WorldServer/Entity.h

@@ -89,28 +89,6 @@ struct DetrimentalEffects {
 	float   total_time;
 };
 
-struct CombatData{
-	int32			range_last_attack_time;
-	int32			primary_last_attack_time;
-	int32			secondary_last_attack_time;
-	int16			primary_attack_delay;
-	int16			secondary_attack_delay;
-	int16			ranged_attack_delay;
-	int8			primary_weapon_type;
-	int8			secondary_weapon_type;
-	int8			ranged_weapon_type;
-	int32			primary_weapon_damage_low;
-	int32			primary_weapon_damage_high;
-	int32			secondary_weapon_damage_low;
-	int32			secondary_weapon_damage_high;
-	int32			ranged_weapon_damage_low;
-	int32			ranged_weapon_damage_high;
-	int8			wield_type;
-	int16           primary_weapon_delay;
-	int16           secondary_weapon_delay;
-	int16           ranged_weapon_delay;
-};
-
 struct InfoStruct{
 	InfoStruct()
 	{
@@ -260,6 +238,31 @@ struct InfoStruct{
 		interaction_flag_ = 0;
 		tag1_ = 0;
 		mood_ = 0;
+		
+		range_last_attack_time_ = 0;
+		primary_last_attack_time_ = 0;
+		secondary_last_attack_time_ = 0;
+		primary_attack_delay_ = 0;
+		secondary_attack_delay_ = 0;
+		ranged_attack_delay_ = 0;
+		primary_weapon_type_ = 0;
+		secondary_weapon_type_ = 0;
+		ranged_weapon_type_ = 0;
+		primary_weapon_damage_low_ = 0;
+		primary_weapon_damage_high_ = 0;
+		secondary_weapon_damage_low_ = 0;
+		secondary_weapon_damage_high_ = 0;
+		ranged_weapon_damage_low_ = 0;
+		ranged_weapon_damage_high_ = 0;
+		wield_type_ = 0;
+		attack_type_ = 0;
+		primary_weapon_delay_ = 0;
+		secondary_weapon_delay_ = 0;
+		ranged_weapon_delay_ = 0;
+		
+		override_primary_weapon_ = 0;
+		override_secondary_weapon_ = 0;
+		override_ranged_weapon_ = 0;
 	}
 
 
@@ -415,6 +418,31 @@ struct InfoStruct{
 		interaction_flag_ = oldStruct->get_interaction_flag();
 		tag1_ = oldStruct->get_tag1();
 		mood_ = oldStruct->get_mood();
+		
+		range_last_attack_time_ = oldStruct->get_range_last_attack_time();
+		primary_last_attack_time_ = oldStruct->get_primary_last_attack_time();;
+		secondary_last_attack_time_ = oldStruct->get_secondary_last_attack_time();;
+		primary_attack_delay_ = oldStruct->get_primary_attack_delay();
+		secondary_attack_delay_ = oldStruct->get_secondary_attack_delay();
+		ranged_attack_delay_ = oldStruct->get_ranged_attack_delay();
+		primary_weapon_type_ = oldStruct->get_primary_weapon_type();
+		secondary_weapon_type_ = oldStruct->get_secondary_weapon_type();
+		ranged_weapon_type_ = oldStruct->get_ranged_weapon_type();
+		primary_weapon_damage_low_ = oldStruct->get_primary_weapon_damage_low();
+		primary_weapon_damage_high_ = oldStruct->get_primary_weapon_damage_high();
+		secondary_weapon_damage_low_ = oldStruct->get_secondary_weapon_damage_low();
+		secondary_weapon_damage_high_ = oldStruct->get_secondary_weapon_damage_high();
+		ranged_weapon_damage_low_ = oldStruct->get_ranged_weapon_damage_low();
+		ranged_weapon_damage_high_ = oldStruct->get_ranged_weapon_damage_high();
+		wield_type_ = oldStruct->get_wield_type();
+		attack_type_ = oldStruct->get_attack_type();
+		primary_weapon_delay_ = oldStruct->get_primary_weapon_delay();
+		secondary_weapon_delay_ = oldStruct->get_secondary_weapon_delay();
+		ranged_weapon_delay_ = oldStruct->get_ranged_weapon_delay();
+		
+		override_primary_weapon_ = oldStruct->get_override_primary_weapon();
+		override_secondary_weapon_ = oldStruct->get_override_secondary_weapon();
+		override_ranged_weapon_ = oldStruct->get_override_ranged_weapon();
 	}
 
 	//mutable std::shared_mutex mutex_;
@@ -581,6 +609,36 @@ struct InfoStruct{
 	int8	get_tag1() { std::lock_guard<std::mutex> lk(classMutex); return tag1_; }
 	int16	get_mood() { std::lock_guard<std::mutex> lk(classMutex); return mood_; }
 
+	int32	get_range_last_attack_time() { std::lock_guard<std::mutex> lk(classMutex); return range_last_attack_time_; }
+	int32	get_primary_last_attack_time() { std::lock_guard<std::mutex> lk(classMutex); return primary_last_attack_time_; }
+	int32	get_secondary_last_attack_time() { std::lock_guard<std::mutex> lk(classMutex); return secondary_last_attack_time_; }
+	
+	int16	get_primary_attack_delay() { std::lock_guard<std::mutex> lk(classMutex); return primary_attack_delay_; }
+	int16	get_secondary_attack_delay() { std::lock_guard<std::mutex> lk(classMutex); return secondary_attack_delay_; }
+	int16	get_ranged_attack_delay() { std::lock_guard<std::mutex> lk(classMutex); return ranged_attack_delay_; }
+	
+	int8	get_primary_weapon_type() { std::lock_guard<std::mutex> lk(classMutex); return primary_weapon_type_; }
+	int8	get_secondary_weapon_type() { std::lock_guard<std::mutex> lk(classMutex); return secondary_weapon_type_; }
+	int8	get_ranged_weapon_type() { std::lock_guard<std::mutex> lk(classMutex); return ranged_weapon_type_; }
+
+	int32	get_primary_weapon_damage_low() { std::lock_guard<std::mutex> lk(classMutex); return primary_weapon_damage_low_; }
+	int32	get_primary_weapon_damage_high() { std::lock_guard<std::mutex> lk(classMutex); return primary_weapon_damage_high_; }
+	int32	get_secondary_weapon_damage_low() { std::lock_guard<std::mutex> lk(classMutex); return secondary_weapon_damage_low_; }
+	int32	get_secondary_weapon_damage_high() { std::lock_guard<std::mutex> lk(classMutex); return secondary_weapon_damage_high_; }
+	int32	get_ranged_weapon_damage_low() { std::lock_guard<std::mutex> lk(classMutex); return ranged_weapon_damage_low_; }
+	int32	get_ranged_weapon_damage_high() { std::lock_guard<std::mutex> lk(classMutex); return ranged_weapon_damage_high_; }
+
+	int8	get_wield_type() { std::lock_guard<std::mutex> lk(classMutex); return wield_type_; }
+	int8	get_attack_type() { std::lock_guard<std::mutex> lk(classMutex); return attack_type_; }
+
+	int16	get_primary_weapon_delay() { std::lock_guard<std::mutex> lk(classMutex); return primary_weapon_delay_; }
+	int16	get_secondary_weapon_delay() { std::lock_guard<std::mutex> lk(classMutex); return primary_weapon_delay_; }
+	int16	get_ranged_weapon_delay() { std::lock_guard<std::mutex> lk(classMutex); return primary_weapon_delay_; }
+	
+	int8	get_override_primary_weapon() { std::lock_guard<std::mutex> lk(classMutex); return override_primary_weapon_; }
+	int8	get_override_secondary_weapon() { std::lock_guard<std::mutex> lk(classMutex); return override_secondary_weapon_; }
+	int8	get_override_ranged_weapon() { std::lock_guard<std::mutex> lk(classMutex); return override_ranged_weapon_; }
+
 	void	set_name(std::string value) { std::lock_guard<std::mutex> lk(classMutex); name_ = value; }
 	
 	void	set_deity(std::string value) { std::lock_guard<std::mutex> lk(classMutex); deity_ = value; }
@@ -830,6 +888,36 @@ struct InfoStruct{
 	void	set_tag1(int8 value) { std::lock_guard<std::mutex> lk(classMutex); tag1_ = value; }
 	void	set_mood(int16 value) { std::lock_guard<std::mutex> lk(classMutex); mood_ = value; }
 
+	void	set_range_last_attack_time(int32 value) { std::lock_guard<std::mutex> lk(classMutex); range_last_attack_time_ = value; }
+	void	set_primary_last_attack_time(int32 value) { std::lock_guard<std::mutex> lk(classMutex); primary_last_attack_time_ = value; }
+	void	set_secondary_last_attack_time(int32 value) { std::lock_guard<std::mutex> lk(classMutex); secondary_last_attack_time_ = value; }
+	
+	void	set_primary_attack_delay(int16 value) { std::lock_guard<std::mutex> lk(classMutex); primary_attack_delay_ = value; }
+	void	set_secondary_attack_delay(int16 value) { std::lock_guard<std::mutex> lk(classMutex); secondary_attack_delay_ = value; }
+	void	set_ranged_attack_delay(int16 value) { std::lock_guard<std::mutex> lk(classMutex); ranged_attack_delay_ = value; }
+
+	void	set_primary_weapon_type(int8 value) { std::lock_guard<std::mutex> lk(classMutex); primary_weapon_type_ = value; }
+	void	set_secondary_weapon_type(int8 value) { std::lock_guard<std::mutex> lk(classMutex); secondary_weapon_type_ = value; }
+	void	set_ranged_weapon_type(int8 value) { std::lock_guard<std::mutex> lk(classMutex); ranged_weapon_type_ = value; }
+	
+	void	set_primary_weapon_damage_low(int32 value) { std::lock_guard<std::mutex> lk(classMutex); primary_weapon_damage_low_ = value; }
+	void	set_primary_weapon_damage_high(int32 value) { std::lock_guard<std::mutex> lk(classMutex); primary_weapon_damage_high_ = value; }
+	void	set_secondary_weapon_damage_low(int32 value) { std::lock_guard<std::mutex> lk(classMutex); secondary_weapon_damage_low_ = value; }
+	void	set_secondary_weapon_damage_high(int32 value) { std::lock_guard<std::mutex> lk(classMutex); secondary_weapon_damage_high_ = value; }
+	void	set_ranged_weapon_damage_low(int32 value) { std::lock_guard<std::mutex> lk(classMutex); ranged_weapon_damage_low_ = value; }
+	void	set_ranged_weapon_damage_high(int32 value) { std::lock_guard<std::mutex> lk(classMutex); ranged_weapon_damage_high_ = value; }
+	
+	void	set_wield_type(int8 value) { std::lock_guard<std::mutex> lk(classMutex); wield_type_ = value; }
+	void	set_attack_type(int8 value) { std::lock_guard<std::mutex> lk(classMutex); attack_type_ = value; }
+	
+	void	set_primary_weapon_delay(int16 value) { std::lock_guard<std::mutex> lk(classMutex); primary_weapon_delay_ = value; }
+	void	set_secondary_weapon_delay(int16 value) { std::lock_guard<std::mutex> lk(classMutex); secondary_weapon_delay_ = value; }
+	void	set_ranged_weapon_delay(int16 value) { std::lock_guard<std::mutex> lk(classMutex); ranged_weapon_delay_ = value; }
+	
+	void	set_override_primary_weapon(int8 value) { std::lock_guard<std::mutex> lk(classMutex); override_secondary_weapon_ = value; }
+	void	set_override_secondary_weapon(int8 value) { std::lock_guard<std::mutex> lk(classMutex); override_secondary_weapon_ = value; }
+	void	set_override_ranged_weapon(int8 value) { std::lock_guard<std::mutex> lk(classMutex); override_ranged_weapon_ = value; }
+	
 	void	ResetEffects(Spawn* spawn)
 	{
 		for(int i=0;i<45;i++){
@@ -1001,6 +1089,32 @@ private:
 	int8			interaction_flag_;
 	int8			tag1_;
 	int16			mood_;
+	
+	int32			range_last_attack_time_;
+	int32			primary_last_attack_time_;
+	int32			secondary_last_attack_time_;
+	int16			primary_attack_delay_;
+	int16			secondary_attack_delay_;
+	int16			ranged_attack_delay_;
+	int8			primary_weapon_type_;
+	int8			secondary_weapon_type_;
+	int8			ranged_weapon_type_;
+	int32			primary_weapon_damage_low_;
+	int32			primary_weapon_damage_high_;
+	int32			secondary_weapon_damage_low_;
+	int32			secondary_weapon_damage_high_;
+	int32			ranged_weapon_damage_low_;
+	int32			ranged_weapon_damage_high_;
+	int8			wield_type_;
+	int8			attack_type_;
+	int16           primary_weapon_delay_;
+	int16           secondary_weapon_delay_;
+	int16           ranged_weapon_delay_;
+	
+	int8			override_primary_weapon_;
+	int8			override_secondary_weapon_;
+	int8			override_ranged_weapon_;
+	
 	// when PacketStruct is fixed for C++17 this should become a shared_mutex and handle read/write lock
 	std::mutex		classMutex;
 };
@@ -1198,19 +1312,19 @@ public:
 	int32	GetRangeLastAttackTime();
 	void	SetRangeLastAttackTime(int32 time);
 	int16	GetRangeAttackDelay();
-	int16   GetRangeWeaponDelay() {return ranged_combat_data.ranged_weapon_delay;}
-	void    SetRangeWeaponDelay(int16 new_delay) {ranged_combat_data.ranged_weapon_delay = new_delay * 100;}
-	void    SetRangeAttackDelay(int16 new_delay) {ranged_combat_data.ranged_attack_delay = new_delay;}
+	int16   GetRangeWeaponDelay();
+	void    SetRangeWeaponDelay(int16 new_delay);
+	void    SetRangeAttackDelay(int16 new_delay);
 	int32	GetPrimaryLastAttackTime();
 	int16	GetPrimaryAttackDelay();
 	void	SetPrimaryAttackDelay(int16 new_delay);
 	void	SetPrimaryLastAttackTime(int32 new_time);
-	void    SetPrimaryWeaponDelay(int16 new_delay) {melee_combat_data.primary_weapon_delay = new_delay * 100;}
+	void    SetPrimaryWeaponDelay(int16 new_delay);
 	int32	GetSecondaryLastAttackTime();
 	int16	GetSecondaryAttackDelay();
 	void	SetSecondaryAttackDelay(int16 new_delay);
 	void	SetSecondaryLastAttackTime(int32 new_time);
-	void    SetSecondaryWeaponDelay(int16 new_delay) {melee_combat_data.primary_weapon_delay = new_delay * 100;}
+	void    SetSecondaryWeaponDelay(int16 new_delay);
 	int32	GetPrimaryWeaponMinDamage();
 	int32	GetPrimaryWeaponMaxDamage();
 	int32	GetSecondaryWeaponMinDamage();
@@ -1221,8 +1335,8 @@ public:
 	int8	GetSecondaryWeaponType();
 	int8	GetRangedWeaponType();
 	int8	GetWieldType();
-	int16   GetPrimaryWeaponDelay() {return melee_combat_data.primary_weapon_delay;}
-	int16   GetSecondaryWeaponDelay() {return melee_combat_data.secondary_weapon_delay;}
+	int16   GetPrimaryWeaponDelay();
+	int16   GetSecondaryWeaponDelay();
 	bool	IsDualWield();
 	bool	BehindTarget(Spawn* target);
 	bool	FlankingTarget(Spawn* target);
@@ -1717,8 +1831,6 @@ private:
 	float	last_heading;
 	bool	casting;
 	InfoStruct		info_struct;
-	CombatData melee_combat_data;
-	CombatData ranged_combat_data;
 	map<int8, int8> det_count_list;
 	Mutex MDetriments;
 	vector<DetrimentalEffects> detrimental_spell_effects;

+ 0 - 6
EQ2/source/WorldServer/NPC.cpp

@@ -81,8 +81,6 @@ NPC::NPC(NPC* old_npc){
 		movement_interrupted = false;
 		old_npc->SetQuestsRequired(this);
 		SetTransporterID(old_npc->GetTransporterID());
-
-		SetAttackType(old_npc->GetAttackType());
 		SetAIStrategy(old_npc->GetAIStrategy());
 		SetPrimarySpellList(old_npc->GetPrimarySpellList());
 		SetSecondarySpellList(old_npc->GetSecondarySpellList());
@@ -729,10 +727,6 @@ Skill* NPC::GetSkillByID(int32 id, bool check_update){
 	return 0;
 }
 
-void NPC::SetAttackType(int8 type){
-	attack_type = type;
-}
-
 int8 NPC::GetAttackType(){
 	return attack_type;
 }

+ 0 - 1
EQ2/source/WorldServer/NPC.h

@@ -90,7 +90,6 @@ public:
 	void	Randomize(NPC* npc, int32 flags);
 	Skill*	GetSkillByName(const char* name, bool check_update = false);
 	Skill*	GetSkillByID(int32 id, bool check_update = false);
-	void	SetAttackType(int8 type);
 	int8	GetAttackType();
 	void	SetAIStrategy(int8 strategy);
 	int8	GetAIStrategy();

+ 2 - 2
EQ2/source/WorldServer/WorldDatabase.cpp

@@ -1030,7 +1030,6 @@ void WorldDatabase::LoadNPCs(ZoneServer* zone){
 		npc->SetMerchantID(atoul(row[37]));
 		npc->SetMerchantType(atoi(row[38]));
 		npc->SetSizeOffset(atoi(row[39]));
-		npc->SetAttackType(atoi(row[40]));
 		npc->SetAIStrategy(atoi(row[41]));
 		npc->SetPrimarySpellList(atoul(row[42]));
 		npc->SetSecondarySpellList(atoul(row[43]));
@@ -1039,6 +1038,7 @@ void WorldDatabase::LoadNPCs(ZoneServer* zone){
 		npc->SetEquipmentListID(atoul(row[46]));
 
 		InfoStruct* info = npc->GetInfoStruct();
+		info->set_attack_type(atoi(row[40]));
 		info->set_str_base(atoi(row[47]));
 		info->set_sta_base(atoi(row[48]));
 		info->set_wis_base(atoi(row[49]));		
@@ -6743,7 +6743,6 @@ bool WorldDatabase::LoadNPC(ZoneServer* zone, int32 spawn_id) {
 		npc->SetMerchantID(result.GetInt32(37));
 		npc->SetMerchantType(result.GetInt8(38));
 		npc->SetSizeOffset(result.GetInt8(39));
-		npc->SetAttackType(result.GetInt8(40));
 		npc->SetAIStrategy(result.GetInt8(41));
 		npc->SetPrimarySpellList(result.GetInt32(42));
 		npc->SetSecondarySpellList(result.GetInt32(43));
@@ -6752,6 +6751,7 @@ bool WorldDatabase::LoadNPC(ZoneServer* zone, int32 spawn_id) {
 		npc->SetEquipmentListID(result.GetInt32(46));
 
 		InfoStruct* info = npc->GetInfoStruct();
+		info->set_attack_type(result.GetInt8(40));
 		info->set_str_base(result.GetInt16(47));
 		info->set_sta_base(result.GetInt16(48));
 		info->set_wis_base(result.GetInt16(49));