mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
Texture work
This commit is contained in:
parent
a24dfd35e8
commit
11a43cd320
@ -1184,15 +1184,15 @@ struct SpecialMesg_Struct
|
||||
** When somebody changes what they're wearing or give a pet a weapon (model changes)
|
||||
** Length: 19 Bytes
|
||||
*/
|
||||
struct WearChange_Struct{
|
||||
/*000*/ uint16 spawn_id;
|
||||
/*002*/ uint32 material;
|
||||
/*006*/ uint32 unknown06;
|
||||
/*010*/ uint32 elite_material; // 1 for Drakkin Elite Material
|
||||
/*014*/ uint32 hero_forge_model; // New to VoA
|
||||
/*018*/ uint32 unknown18; // New to RoF
|
||||
struct WearChange_Struct {
|
||||
/*000*/ uint16 spawn_id;
|
||||
/*002*/ uint32 material;
|
||||
/*006*/ uint32 unknown06;
|
||||
/*010*/ uint32 elite_material; // 1 for Drakkin Elite Material
|
||||
/*014*/ uint32 hero_forge_model; // New to VoA
|
||||
/*018*/ uint32 unknown18; // New to RoF
|
||||
/*022*/ EQEmu::textures::Tint_Struct color;
|
||||
/*026*/ uint8 wear_slot_id;
|
||||
/*026*/ uint8 wear_slot_id;
|
||||
/*027*/
|
||||
};
|
||||
|
||||
|
||||
@ -93,6 +93,7 @@ namespace Logs {
|
||||
Traps,
|
||||
NPCRoamBox,
|
||||
NPCScaling,
|
||||
MobAppearance,
|
||||
MaxCategoryID /* Don't Remove this */
|
||||
};
|
||||
|
||||
@ -151,7 +152,8 @@ namespace Logs {
|
||||
"Food",
|
||||
"Traps",
|
||||
"NPC Roam Box",
|
||||
"NPC Scaling"
|
||||
"NPC Scaling",
|
||||
"Mob Appearance"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -84,6 +84,7 @@ EQEmu::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
|
||||
m_ornamentidfile = 0;
|
||||
m_ornament_hero_model = 0;
|
||||
m_recast_timestamp = 0;
|
||||
m_new_id_file = 0;
|
||||
}
|
||||
|
||||
EQEmu::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
|
||||
@ -117,6 +118,7 @@ EQEmu::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 char
|
||||
m_ornamentidfile = 0;
|
||||
m_ornament_hero_model = 0;
|
||||
m_recast_timestamp = 0;
|
||||
m_new_id_file = 0;
|
||||
}
|
||||
|
||||
EQEmu::ItemInstance::ItemInstance(ItemInstTypes use_type) {
|
||||
@ -138,6 +140,7 @@ EQEmu::ItemInstance::ItemInstance(ItemInstTypes use_type) {
|
||||
m_ornamentidfile = 0;
|
||||
m_ornament_hero_model = 0;
|
||||
m_recast_timestamp = 0;
|
||||
m_new_id_file = 0;
|
||||
}
|
||||
|
||||
// Make a copy of an EQEmu::ItemInstance object
|
||||
@ -195,6 +198,7 @@ EQEmu::ItemInstance::ItemInstance(const ItemInstance& copy)
|
||||
m_ornamentidfile = copy.m_ornamentidfile;
|
||||
m_ornament_hero_model = copy.m_ornament_hero_model;
|
||||
m_recast_timestamp = copy.m_recast_timestamp;
|
||||
m_new_id_file = copy.m_new_id_file;
|
||||
}
|
||||
|
||||
// Clean up container contents
|
||||
|
||||
@ -203,6 +203,8 @@ namespace EQEmu
|
||||
void SetOrnamentIcon(uint32 ornament_icon) { m_ornamenticon = ornament_icon; }
|
||||
uint32 GetOrnamentationIDFile() const { return m_ornamentidfile; }
|
||||
void SetOrnamentationIDFile(uint32 ornament_idfile) { m_ornamentidfile = ornament_idfile; }
|
||||
uint32 GetNewIDFile() const { return m_new_id_file; }
|
||||
void SetNewIDFile(uint32 new_id_file) { m_new_id_file = new_id_file; }
|
||||
uint32 GetOrnamentHeroModel(int32 material_slot = -1) const;
|
||||
void SetOrnamentHeroModel(uint32 ornament_hero_model) { m_ornament_hero_model = ornament_hero_model; }
|
||||
uint32 GetRecastTimestamp() const { return m_recast_timestamp; }
|
||||
@ -306,6 +308,7 @@ namespace EQEmu
|
||||
bool m_scaling;
|
||||
uint32 m_ornamenticon;
|
||||
uint32 m_ornamentidfile;
|
||||
uint32 m_new_id_file;
|
||||
uint32 m_ornament_hero_model;
|
||||
uint32 m_recast_timestamp;
|
||||
|
||||
|
||||
@ -5488,8 +5488,16 @@ namespace RoF2
|
||||
ob.write(item->Lore, strlen(item->Lore));
|
||||
ob.write("\0", 1);
|
||||
|
||||
if (strlen(item->IDFile) > 0)
|
||||
if (inst->GetNewIDFile() > 0) {
|
||||
char new_id_file[30];
|
||||
memset(new_id_file, 0x0, 30);
|
||||
sprintf(new_id_file, "IT%d", inst->GetNewIDFile());
|
||||
ob.write(new_id_file, strlen(new_id_file));
|
||||
}
|
||||
else if (strlen(item->IDFile) > 0) {
|
||||
ob.write(item->IDFile, strlen(item->IDFile));
|
||||
}
|
||||
|
||||
ob.write("\0", 1);
|
||||
|
||||
ob.write("\0", 1);
|
||||
|
||||
@ -65,6 +65,12 @@ namespace EQEmu
|
||||
uint32 Unknown2; // same as material?
|
||||
};
|
||||
|
||||
struct InternalTexture_Struct {
|
||||
uint32 HerosForgeModel;
|
||||
uint32 Material;
|
||||
uint32 Color;
|
||||
};
|
||||
|
||||
struct TextureMaterial_Struct {
|
||||
uint32 Material;
|
||||
};
|
||||
@ -100,6 +106,23 @@ namespace EQEmu
|
||||
};
|
||||
};
|
||||
|
||||
struct InternalTextureProfile {
|
||||
union {
|
||||
struct {
|
||||
textures::InternalTexture_Struct Head;
|
||||
textures::InternalTexture_Struct Chest;
|
||||
textures::InternalTexture_Struct Arms;
|
||||
textures::InternalTexture_Struct Wrist;
|
||||
textures::InternalTexture_Struct Hands;
|
||||
textures::InternalTexture_Struct Legs;
|
||||
textures::InternalTexture_Struct Feet;
|
||||
textures::InternalTexture_Struct Primary;
|
||||
textures::InternalTexture_Struct Secondary;
|
||||
};
|
||||
textures::InternalTexture_Struct Slot[textures::materialCount];
|
||||
};
|
||||
};
|
||||
|
||||
struct TextureMaterialProfile {
|
||||
union {
|
||||
struct {
|
||||
|
||||
@ -82,6 +82,7 @@ SET(zone_sources
|
||||
merc.cpp
|
||||
mob.cpp
|
||||
mob_ai.cpp
|
||||
mob_appearance.cpp
|
||||
mob_movement_manager.cpp
|
||||
mob_info.cpp
|
||||
mod_functions.cpp
|
||||
|
||||
18
zone/aa.cpp
18
zone/aa.cpp
@ -286,7 +286,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
make_npc->min_dmg = 1;
|
||||
|
||||
//base stats
|
||||
make_npc->cur_hp = (GetLevel() * 55);
|
||||
make_npc->current_hp = (GetLevel() * 55);
|
||||
make_npc->max_hp = (GetLevel() * 55);
|
||||
make_npc->STR = 85 + (GetLevel() * 3);
|
||||
make_npc->STA = 85 + (GetLevel() * 3);
|
||||
@ -356,51 +356,51 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
|
||||
case PALADIN:
|
||||
//SPECATK_TRIPLE
|
||||
strcpy(make_npc->special_abilities, "6,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 150 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 150 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 150 / 100;
|
||||
make_npc->npc_spells_id = 8;
|
||||
break;
|
||||
case SHADOWKNIGHT:
|
||||
strcpy(make_npc->special_abilities, "6,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 150 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 150 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 150 / 100;
|
||||
make_npc->npc_spells_id = 9;
|
||||
break;
|
||||
case RANGER:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 135 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 135 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 135 / 100;
|
||||
make_npc->npc_spells_id = 10;
|
||||
break;
|
||||
case BARD:
|
||||
strcpy(make_npc->special_abilities, "6,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 110 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 110 / 100;
|
||||
make_npc->npc_spells_id = 11;
|
||||
break;
|
||||
case BEASTLORD:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 110 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 110 / 100;
|
||||
make_npc->npc_spells_id = 12;
|
||||
break;
|
||||
case ROGUE:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
|
||||
make_npc->cur_hp = make_npc->cur_hp * 110 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 110 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 110 / 100;
|
||||
break;
|
||||
case MONK:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
|
||||
make_npc->cur_hp = make_npc->cur_hp * 135 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 135 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 135 / 100;
|
||||
break;
|
||||
case WARRIOR:
|
||||
case BERSERKER:
|
||||
strcpy(make_npc->special_abilities, "7,1");
|
||||
make_npc->max_dmg = make_npc->max_dmg * 150 /100;
|
||||
make_npc->cur_hp = make_npc->cur_hp * 175 / 100;
|
||||
make_npc->current_hp = make_npc->current_hp * 175 / 100;
|
||||
make_npc->max_hp = make_npc->max_hp * 175 / 100;
|
||||
break;
|
||||
default:
|
||||
|
||||
@ -33,6 +33,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "zone.h"
|
||||
#include "lua_parser.h"
|
||||
#include "fastmath.h"
|
||||
#include "mob.h"
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
@ -5444,7 +5446,7 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
||||
// For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true
|
||||
if ((GetSpecialAbility(SPECATK_INNATE_DW) ||
|
||||
(RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SPECATK_QUAD))) ||
|
||||
GetEquipment(EQEmu::textures::weaponSecondary) != 0) {
|
||||
GetEquippedItemFromTextureSlot(EQEmu::textures::weaponSecondary) != 0) {
|
||||
if (CheckDualWield()) {
|
||||
Attack(target, EQEmu::invslot::slotSecondary, false, false, false, opts);
|
||||
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack()) {
|
||||
@ -5476,4 +5478,4 @@ int32 Mob::GetHPRegen() const
|
||||
int32 Mob::GetManaRegen() const
|
||||
{
|
||||
return mana_regen;
|
||||
}
|
||||
}
|
||||
@ -2965,13 +2965,12 @@ bool Client::BindWound(Mob *bindmob, bool start, bool fail)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::SetMaterial(int16 in_slot, uint32 item_id) {
|
||||
const EQEmu::ItemData* item = database.GetItem(item_id);
|
||||
if (item && item->IsClassCommon())
|
||||
{
|
||||
void Client::SetMaterial(int16 in_slot, uint32 item_id)
|
||||
{
|
||||
const EQEmu::ItemData *item = database.GetItem(item_id);
|
||||
if (item && item->IsClassCommon()) {
|
||||
uint8 matslot = EQEmu::InventoryProfile::CalcMaterialFromSlot(in_slot);
|
||||
if (matslot != EQEmu::textures::materialInvalid)
|
||||
{
|
||||
if (matslot != EQEmu::textures::materialInvalid) {
|
||||
m_pp.item_material.Slot[matslot].Material = GetEquipmentMaterial(matslot);
|
||||
}
|
||||
}
|
||||
@ -8527,11 +8526,11 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold,
|
||||
}
|
||||
|
||||
void Client::SendHPUpdateMarquee(){
|
||||
if (!this || !this->IsClient() || !this->cur_hp || !this->max_hp)
|
||||
if (!this || !this->IsClient() || !this->current_hp || !this->max_hp)
|
||||
return;
|
||||
|
||||
/* Health Update Marquee Display: Custom*/
|
||||
uint8 health_percentage = (uint8)(this->cur_hp * 100 / this->max_hp);
|
||||
uint8 health_percentage = (uint8)(this->current_hp * 100 / this->max_hp);
|
||||
if (health_percentage >= 100)
|
||||
return;
|
||||
|
||||
|
||||
@ -352,7 +352,7 @@ public:
|
||||
void SetHideMe(bool hm);
|
||||
inline uint16 GetPort() const { return port; }
|
||||
bool IsDead() const { return(dead); }
|
||||
bool IsUnconscious() const { return ((cur_hp <= 0) ? true : false); }
|
||||
bool IsUnconscious() const { return ((current_hp <= 0) ? true : false); }
|
||||
inline bool IsLFP() { return LFP; }
|
||||
void UpdateLFP();
|
||||
|
||||
@ -798,7 +798,7 @@ public:
|
||||
#ifdef PACKET_PROFILER
|
||||
void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); }
|
||||
#endif
|
||||
uint32 GetEquipment(uint8 material_slot) const; // returns item id
|
||||
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); }
|
||||
|
||||
|
||||
@ -325,15 +325,15 @@ int32 Client::CalcMaxHP()
|
||||
max_hp += spellbonuses.HP + aabonuses.HP;
|
||||
max_hp += GroupLeadershipAAHealthEnhancement();
|
||||
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
|
||||
if (cur_hp > max_hp) {
|
||||
cur_hp = max_hp;
|
||||
if (current_hp > max_hp) {
|
||||
current_hp = max_hp;
|
||||
}
|
||||
int hp_perc_cap = spellbonuses.HPPercCap[0];
|
||||
if (hp_perc_cap) {
|
||||
int curHP_cap = (max_hp * hp_perc_cap) / 100;
|
||||
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1])) {
|
||||
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1])) {
|
||||
|
||||
cur_hp = curHP_cap;
|
||||
current_hp = curHP_cap;
|
||||
}
|
||||
}
|
||||
return max_hp;
|
||||
|
||||
@ -3237,42 +3237,40 @@ void Client::Handle_OP_AutoAttack(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->pBuffer[0] == 0)
|
||||
{
|
||||
if (app->pBuffer[0] == 0) {
|
||||
auto_attack = false;
|
||||
if (IsAIControlled())
|
||||
if (IsAIControlled()) {
|
||||
return;
|
||||
}
|
||||
attack_timer.Disable();
|
||||
ranged_timer.Disable();
|
||||
attack_dw_timer.Disable();
|
||||
|
||||
m_AutoAttackPosition = glm::vec4();
|
||||
m_AutoAttackPosition = glm::vec4();
|
||||
m_AutoAttackTargetLocation = glm::vec3();
|
||||
aa_los_them_mob = nullptr;
|
||||
aa_los_them_mob = nullptr;
|
||||
}
|
||||
else if (app->pBuffer[0] == 1)
|
||||
{
|
||||
else if (app->pBuffer[0] == 1) {
|
||||
auto_attack = true;
|
||||
auto_fire = false;
|
||||
if (IsAIControlled())
|
||||
auto_fire = false;
|
||||
if (IsAIControlled()) {
|
||||
return;
|
||||
}
|
||||
SetAttackTimer();
|
||||
|
||||
if (GetTarget())
|
||||
{
|
||||
aa_los_them_mob = GetTarget();
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
if (GetTarget()) {
|
||||
aa_los_them_mob = GetTarget();
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
|
||||
los_status = CheckLosFN(aa_los_them_mob);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
los_status = CheckLosFN(aa_los_them_mob);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
else {
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation = glm::vec3();
|
||||
aa_los_them_mob = nullptr;
|
||||
los_status = false;
|
||||
los_status_facing = false;
|
||||
aa_los_them_mob = nullptr;
|
||||
los_status = false;
|
||||
los_status_facing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14452,7 +14450,6 @@ void Client::Handle_OP_WearChange(const EQApplicationPacket *app)
|
||||
|
||||
// we could maybe ignore this and just send our own from moveitem
|
||||
entity_list.QueueClients(this, app, true);
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_WhoAllRequest(const EQApplicationPacket *app)
|
||||
|
||||
@ -345,25 +345,22 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
Mob *auto_attack_target = GetTarget();
|
||||
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check())
|
||||
{
|
||||
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check()) {
|
||||
//check if change
|
||||
//only check on primary attack.. sorry offhand you gotta wait!
|
||||
if (aa_los_them_mob)
|
||||
{
|
||||
if (aa_los_them_mob) {
|
||||
if (auto_attack_target != aa_los_them_mob ||
|
||||
m_AutoAttackPosition.x != GetX() ||
|
||||
m_AutoAttackPosition.y != GetY() ||
|
||||
m_AutoAttackPosition.z != GetZ() ||
|
||||
m_AutoAttackTargetLocation.x != aa_los_them_mob->GetX() ||
|
||||
m_AutoAttackTargetLocation.y != aa_los_them_mob->GetY() ||
|
||||
m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ())
|
||||
{
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation.z != aa_los_them_mob->GetZ()) {
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
}
|
||||
// If only our heading changes, we can skip the CheckLosFN call
|
||||
// but above we still need to update los_status_facing
|
||||
@ -372,25 +369,21 @@ bool Client::Process() {
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
else {
|
||||
aa_los_them_mob = auto_attack_target;
|
||||
m_AutoAttackPosition = GetPosition();
|
||||
m_AutoAttackTargetLocation = glm::vec3(aa_los_them_mob->GetPosition());
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
los_status = CheckLosFN(auto_attack_target);
|
||||
los_status_facing = IsFacingMob(aa_los_them_mob);
|
||||
}
|
||||
|
||||
if (!CombatRange(auto_attack_target))
|
||||
{
|
||||
if (!CombatRange(auto_attack_target)) {
|
||||
Message_StringID(MT_TooFarAway, TARGET_TOO_FAR);
|
||||
}
|
||||
else if (auto_attack_target == this)
|
||||
{
|
||||
else if (auto_attack_target == this) {
|
||||
Message_StringID(MT_TooFarAway, TRY_ATTACKING_SOMEONE);
|
||||
}
|
||||
else if (!los_status || !los_status_facing)
|
||||
{
|
||||
else if (!los_status || !los_status_facing) {
|
||||
//you can't see your target
|
||||
}
|
||||
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
|
||||
@ -400,8 +393,9 @@ bool Client::Process() {
|
||||
TriggerDefensiveProcs(auto_attack_target, EQEmu::invslot::slotPrimary, false);
|
||||
|
||||
DoAttackRounds(auto_attack_target, EQEmu::invslot::slotPrimary);
|
||||
if (CheckAATimer(aaTimerRampage))
|
||||
if (CheckAATimer(aaTimerRampage)) {
|
||||
entity_list.AEAttack(this, 30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
127
zone/command.cpp
127
zone/command.cpp
@ -249,6 +249,7 @@ int command_init(void)
|
||||
command_add("itemsearch", "[search criteria] - Search for an item", 10, command_itemsearch) ||
|
||||
command_add("kick", "[charname] - Disconnect charname", 150, command_kick) ||
|
||||
command_add("kill", "- Kill your target", 100, command_kill) ||
|
||||
command_add("killallnpcs", "- Kills all npcs, also takes an optional npc name as parameter", 200, command_killallnpcs) ||
|
||||
command_add("lastname", "[new lastname] - Set your or your player target's lastname", 50, command_lastname) ||
|
||||
command_add("level", "[level] - Set your or your target's level", 10, command_level) ||
|
||||
command_add("listnpcs", "[name/range] - Search NPCs", 20, command_listnpcs) ||
|
||||
@ -388,6 +389,7 @@ int command_init(void)
|
||||
command_add("tattoo", "- Change the tattoo of your target (Drakkin Only)", 80, command_tattoo) ||
|
||||
command_add("tempname", "[newname] - Temporarily renames your target. Leave name blank to restore the original name.", 100, command_tempname) ||
|
||||
command_add("petname", "[newname] - Temporarily renames your pet. Leave name blank to restore the original name.", 100, command_petname) ||
|
||||
command_add("test", "Test command", 200, command_test) ||
|
||||
command_add("texture", "[texture] [helmtexture] - Change your or your target's appearance, use 255 to show equipment", 10, command_texture) ||
|
||||
command_add("time", "[HH] [MM] - Set EQ time", 90, command_time) ||
|
||||
command_add("timers", "- Display persistent timers for target", 200, command_timers) ||
|
||||
@ -748,21 +750,21 @@ void command_serversidename(Client *c, const Seperator *sep)
|
||||
|
||||
void command_wc(Client *c, const Seperator *sep)
|
||||
{
|
||||
if(sep->argnum < 2)
|
||||
{
|
||||
c->Message(0, "Usage: #wc [wear slot] [material] [ [hero_forge_model] [elite_material] [unknown06] [unknown18] ]");
|
||||
if (sep->argnum < 2) {
|
||||
c->Message(
|
||||
0,
|
||||
"Usage: #wc [wear slot] [material] [ [hero_forge_model] [elite_material] [unknown06] [unknown18] ]"
|
||||
);
|
||||
}
|
||||
else if(c->GetTarget() == nullptr) {
|
||||
else if (c->GetTarget() == nullptr) {
|
||||
c->Message(13, "You must have a target to do a wear change.");
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
uint32 hero_forge_model = 0;
|
||||
uint32 wearslot = atoi(sep->arg[1]);
|
||||
uint32 wearslot = atoi(sep->arg[1]);
|
||||
|
||||
// Hero Forge
|
||||
if (sep->argnum > 2)
|
||||
{
|
||||
if (sep->argnum > 2) {
|
||||
hero_forge_model = atoi(sep->arg[3]);
|
||||
|
||||
if (hero_forge_model != 0 && hero_forge_model < 1000) {
|
||||
@ -778,45 +780,43 @@ void command_wc(Client *c, const Seperator *sep)
|
||||
else
|
||||
Color = c->GetTarget()->GetArmorTint(atoi(sep->arg[1]));
|
||||
*/
|
||||
c->GetTarget()->SendTextureWC(wearslot, atoi(sep->arg[2]), hero_forge_model, atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]));
|
||||
c->GetTarget()->SendTextureWC(
|
||||
wearslot,
|
||||
atoi(sep->arg[2]),
|
||||
hero_forge_model,
|
||||
atoi(sep->arg[4]),
|
||||
atoi(sep->arg[5]),
|
||||
atoi(sep->arg[6]));
|
||||
}
|
||||
}
|
||||
|
||||
void command_heromodel(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (sep->argnum < 1)
|
||||
{
|
||||
if (sep->argnum < 1) {
|
||||
c->Message(0, "Usage: #heromodel [hero forge model] [ [slot] ] (example: #heromodel 63)");
|
||||
}
|
||||
else if (c->GetTarget() == nullptr)
|
||||
{
|
||||
else if (c->GetTarget() == nullptr) {
|
||||
c->Message(13, "You must have a target to do a wear change for Hero's Forge Models.");
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
uint32 hero_forge_model = atoi(sep->arg[1]);
|
||||
|
||||
if (sep->argnum > 1)
|
||||
{
|
||||
uint8 wearslot = (uint8)atoi(sep->arg[2]);
|
||||
if (sep->argnum > 1) {
|
||||
uint8 wearslot = (uint8) atoi(sep->arg[2]);
|
||||
c->GetTarget()->SendTextureWC(wearslot, 0, hero_forge_model, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hero_forge_model > 0)
|
||||
{
|
||||
else {
|
||||
if (hero_forge_model > 0) {
|
||||
// Conversion to simplify the command arguments
|
||||
// Hero's Forge model is actually model * 1000 + texture * 100 + wearslot
|
||||
// Hero's Forge Model slot 7 is actually for Robes, but it still needs to use wearslot 1 in the packet
|
||||
hero_forge_model *= 100;
|
||||
|
||||
for (uint8 wearslot = 0; wearslot < 7; wearslot++)
|
||||
{
|
||||
for (uint8 wearslot = 0; wearslot < 7; wearslot++) {
|
||||
c->GetTarget()->SendTextureWC(wearslot, 0, (hero_forge_model + wearslot), 0, 0, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
c->Message(13, "Hero's Forge Model must be greater than 0.");
|
||||
}
|
||||
}
|
||||
@ -827,12 +827,14 @@ void command_setanim(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (c->GetTarget() && sep->IsNumber(1)) {
|
||||
int num = atoi(sep->arg[1]);
|
||||
if(num < 0 || num >= _eaMaxAppearance) {
|
||||
c->Message(0, "Invalid animation number, between 0 and %d", _eaMaxAppearance-1);
|
||||
if (num < 0 || num >= _eaMaxAppearance) {
|
||||
c->Message(0, "Invalid animation number, between 0 and %d", _eaMaxAppearance - 1);
|
||||
}
|
||||
c->GetTarget()->SetAppearance(EmuAppearance(num));
|
||||
} else
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Usage: #setanim [animnum]");
|
||||
}
|
||||
}
|
||||
|
||||
void command_serverinfo(Client *c, const Seperator *sep)
|
||||
@ -2728,18 +2730,21 @@ void command_setskillall(Client *c, const Seperator *sep)
|
||||
|
||||
void command_race(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *t=c->CastToMob();
|
||||
Mob *target = c->CastToMob();
|
||||
|
||||
if (sep->IsNumber(1)) {
|
||||
auto race = atoi(sep->arg[1]);
|
||||
if ((race >= 0 && race <= 732) || (race >= 2253 && race <= 2259)) {
|
||||
if ((c->GetTarget()) && c->Admin() >= commandRaceOthers)
|
||||
t = c->GetTarget();
|
||||
t->SendIllusionPacket(race);
|
||||
} else {
|
||||
if ((c->GetTarget()) && c->Admin() >= commandRaceOthers) {
|
||||
target = c->GetTarget();
|
||||
}
|
||||
target->SendIllusionPacket(race);
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Usage: #race [0-732, 2253-2259] (0 for back to normal)");
|
||||
}
|
||||
}
|
||||
@ -2817,6 +2822,21 @@ void command_spawn(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void command_test(Client *c, const Seperator *sep)
|
||||
{
|
||||
c->Message(15, "Triggering test command");
|
||||
|
||||
// EQEmu::ItemInstance* fake_weapon_secondary = database.CreateItem(static_cast<uint32>(c->GetItemIDAt(EQEmu::invslot::slotSecondary)));
|
||||
// fake_weapon_secondary->SetNewIDFile(c->GetEquipmentMaterial(EQEmu::textures::weaponSecondary));
|
||||
// c->SendItemPacket(EQEmu::invslot::slotSecondary, fake_weapon_secondary, ItemPacketTrade);
|
||||
// safe_delete(fake_weapon_secondary);
|
||||
|
||||
EQEmu::ItemInstance* fake_weapon = database.CreateItem(static_cast<uint32>(c->GetItemIDAt(EQEmu::invslot::slotPrimary)));
|
||||
fake_weapon->SetNewIDFile(c->GetEquipmentMaterial(EQEmu::textures::weaponPrimary));
|
||||
c->SendItemPacket(EQEmu::invslot::slotPrimary, fake_weapon, ItemPacketTrade);
|
||||
safe_delete(fake_weapon);
|
||||
}
|
||||
|
||||
void command_texture(Client *c, const Seperator *sep)
|
||||
{
|
||||
|
||||
@ -5111,6 +5131,41 @@ void command_kill(Client *c, const Seperator *sep)
|
||||
c->GetTarget()->Kill();
|
||||
}
|
||||
|
||||
void command_killallnpcs(Client *c, const Seperator *sep)
|
||||
{
|
||||
std::string search_string;
|
||||
if (sep->arg[1]) {
|
||||
search_string = sep->arg[1];
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (auto &itr : entity_list.GetMobList()) {
|
||||
Mob *entity = itr.second;
|
||||
if (!entity->IsNPC()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string entity_name = entity->GetName();
|
||||
|
||||
/**
|
||||
* Filter by name
|
||||
*/
|
||||
if (search_string.length() > 0 && entity_name.find(search_string) == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entity->IsInvisible() || !entity->IsAttackAllowed(c)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entity->Damage(c, 1000000000, 0, EQEmu::skills::SkillDragonPunch);
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
c->Message(15, "Killed (%i) npc(s)", count);
|
||||
}
|
||||
|
||||
void command_haste(Client *c, const Seperator *sep)
|
||||
{
|
||||
// #haste command to set client attack speed. Takes a percentage (100 = twice normal attack speed)
|
||||
|
||||
@ -149,6 +149,7 @@ void command_iteminfo(Client *c, const Seperator *sep);
|
||||
void command_itemsearch(Client *c, const Seperator *sep);
|
||||
void command_itemtest(Client *c, const Seperator *sep);
|
||||
void command_kick(Client *c, const Seperator *sep);
|
||||
void command_killallnpcs(Client *c, const Seperator *sep);
|
||||
void command_kill(Client *c, const Seperator *sep);
|
||||
void command_lastname(Client *c, const Seperator *sep);
|
||||
void command_level(Client *c, const Seperator *sep);
|
||||
@ -297,6 +298,7 @@ void command_task(Client *c, const Seperator *sep);
|
||||
void command_tattoo(Client *c, const Seperator *sep);
|
||||
void command_tempname(Client *c, const Seperator *sep);
|
||||
void command_petname(Client *c, const Seperator *sep);
|
||||
void command_test(Client *c, const Seperator *sep);
|
||||
void command_testspawn(Client *c, const Seperator *sep);
|
||||
void command_testspawnkill(Client *c, const Seperator *sep);
|
||||
void command_texture(Client *c, const Seperator *sep);
|
||||
|
||||
@ -1479,7 +1479,7 @@ void Corpse::Spawn() {
|
||||
safe_delete(app);
|
||||
}
|
||||
|
||||
uint32 Corpse::GetEquipment(uint8 material_slot) const {
|
||||
uint32 Corpse::GetEquippedItemFromTextureSlot(uint8 material_slot) const {
|
||||
int16 invslot;
|
||||
|
||||
if (material_slot > EQEmu::textures::LastTexture) {
|
||||
@ -1500,7 +1500,7 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
if(item != 0) {
|
||||
return (item_tint.Slot[material_slot].UseTint ? item_tint.Slot[material_slot].Color : item->Color);
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ class Corpse : public Mob {
|
||||
void Spawn();
|
||||
|
||||
char corpse_name[64];
|
||||
uint32 GetEquipment(uint8 material_slot) const;
|
||||
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const;
|
||||
uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
inline int GetRezExp() { return rez_experience; }
|
||||
|
||||
|
||||
@ -1274,32 +1274,35 @@ void EntityList::SendZoneSpawns(Client *client)
|
||||
|
||||
void EntityList::SendZoneSpawnsBulk(Client *client)
|
||||
{
|
||||
NewSpawn_Struct ns;
|
||||
Mob *spawn;
|
||||
uint32 maxspawns = 100;
|
||||
NewSpawn_Struct ns{};
|
||||
Mob *spawn;
|
||||
EQApplicationPacket *app;
|
||||
|
||||
if (maxspawns > mob_list.size())
|
||||
maxspawns = mob_list.size();
|
||||
auto bzsp = new BulkZoneSpawnPacket(client, maxspawns);
|
||||
uint32 max_spawns = 100;
|
||||
|
||||
if (max_spawns > mob_list.size()) {
|
||||
max_spawns = static_cast<uint32>(mob_list.size());
|
||||
}
|
||||
|
||||
auto bulk_zone_spawn_packet = new BulkZoneSpawnPacket(client, max_spawns);
|
||||
const glm::vec4 &client_position = client->GetPosition();
|
||||
const float distance_max = (600.0 * 600.0);
|
||||
|
||||
bool delaypkt = false;
|
||||
const glm::vec4& cpos = client->GetPosition();
|
||||
const float dmax = 600.0 * 600.0;
|
||||
for (auto it = mob_list.begin(); it != mob_list.end(); ++it) {
|
||||
spawn = it->second;
|
||||
if (spawn && spawn->GetID() > 0 && spawn->Spawned()) {
|
||||
if (!spawn->ShouldISpawnFor(client))
|
||||
if (!spawn->ShouldISpawnFor(client)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 1
|
||||
const glm::vec4& spos = spawn->GetPosition();
|
||||
const glm::vec4 &spawn_position = spawn->GetPosition();
|
||||
|
||||
delaypkt = false;
|
||||
if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE)))
|
||||
delaypkt = true;
|
||||
bool is_delayed_packet = (
|
||||
DistanceSquared(client_position, spawn_position) > distance_max ||
|
||||
(spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE))
|
||||
);
|
||||
|
||||
if (delaypkt) {
|
||||
if (is_delayed_packet) {
|
||||
app = new EQApplicationPacket;
|
||||
spawn->CreateSpawnPacket(app);
|
||||
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||
@ -1308,35 +1311,38 @@ void EntityList::SendZoneSpawnsBulk(Client *client)
|
||||
else {
|
||||
memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
spawn->FillSpawnStruct(&ns, client);
|
||||
bzsp->AddSpawn(&ns);
|
||||
bulk_zone_spawn_packet->AddSpawn(&ns);
|
||||
}
|
||||
|
||||
spawn->SendArmorAppearance(client);
|
||||
#else
|
||||
/* original code kept for spawn packet research */
|
||||
int32 race = spawn->GetRace();
|
||||
|
||||
// Illusion races on PCs don't work as a mass spawn
|
||||
// But they will work as an add_spawn AFTER CLIENT_CONNECTED.
|
||||
if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
|
||||
app = new EQApplicationPacket;
|
||||
spawn->CreateSpawnPacket(app);
|
||||
client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||
safe_delete(app);
|
||||
}
|
||||
else {
|
||||
memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
spawn->FillSpawnStruct(&ns, client);
|
||||
bzsp->AddSpawn(&ns);
|
||||
}
|
||||
|
||||
// Despite being sent in the OP_ZoneSpawns packet, the client
|
||||
// does not display worn armor correctly so display it.
|
||||
spawn->SendArmorAppearance(client);
|
||||
#endif
|
||||
/**
|
||||
* Original code kept for spawn packet research
|
||||
*
|
||||
* int32 race = spawn->GetRace();
|
||||
*
|
||||
* Illusion races on PCs don't work as a mass spawn
|
||||
* But they will work as an add_spawn AFTER CLIENT_CONNECTED.
|
||||
* if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) {
|
||||
* app = new EQApplicationPacket;
|
||||
* spawn->CreateSpawnPacket(app);
|
||||
* client->QueuePacket(app, true, Client::CLIENT_CONNECTED);
|
||||
* safe_delete(app);
|
||||
* }
|
||||
* else {
|
||||
* memset(&ns, 0, sizeof(NewSpawn_Struct));
|
||||
* spawn->FillSpawnStruct(&ns, client);
|
||||
* bzsp->AddSpawn(&ns);
|
||||
* }
|
||||
*
|
||||
* Despite being sent in the OP_ZoneSpawns packet, the client
|
||||
* does not display worn armor correctly so display it.
|
||||
* spawn->SendArmorAppearance(client);
|
||||
*/
|
||||
}
|
||||
}
|
||||
safe_delete(bzsp);
|
||||
|
||||
safe_delete(bulk_zone_spawn_packet);
|
||||
}
|
||||
|
||||
//this is a hack to handle a broken spawn struct
|
||||
@ -3967,8 +3973,9 @@ Mob *EntityList::GetTargetForMez(Mob *caster)
|
||||
|
||||
void EntityList::SendZoneAppearance(Client *c)
|
||||
{
|
||||
if (!c)
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
@ -3983,7 +3990,7 @@ void EntityList::SendZoneAppearance(Client *c)
|
||||
cur->SendAppearancePacket(AT_Anim, cur->GetAppearanceValue(cur->GetAppearance()), false, true, c);
|
||||
}
|
||||
if (cur->GetSize() != cur->GetBaseSize()) {
|
||||
cur->SendAppearancePacket(AT_Size, (uint32)cur->GetSize(), false, true, c);
|
||||
cur->SendAppearancePacket(AT_Size, (uint32) cur->GetSize(), false, true, c);
|
||||
}
|
||||
}
|
||||
++it;
|
||||
|
||||
@ -90,7 +90,7 @@ const NPCType *Horse::BuildHorseType(uint16 spell_id) {
|
||||
strcpy(npc_type->name, "Unclaimed_Mount"); // this should never get used
|
||||
|
||||
strcpy(npc_type->special_abilities, "19,1^20,1^24,1");
|
||||
npc_type->cur_hp = 1;
|
||||
npc_type->current_hp = 1;
|
||||
npc_type->max_hp = 1;
|
||||
npc_type->race = atoi(row[0]);
|
||||
npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck.
|
||||
|
||||
@ -2858,26 +2858,24 @@ void Client::MoveSlotNotAllowed(bool client_update)
|
||||
}
|
||||
|
||||
// these functions operate with a material slot, which is from 0 to 8
|
||||
uint32 Client::GetEquipment(uint8 material_slot) const
|
||||
uint32 Client::GetEquippedItemFromTextureSlot(uint8 material_slot) const
|
||||
{
|
||||
int16 invslot;
|
||||
int16 inventory_slot;
|
||||
|
||||
const EQEmu::ItemInstance *item;
|
||||
|
||||
if(material_slot > EQEmu::textures::LastTexture)
|
||||
{
|
||||
if (material_slot > EQEmu::textures::LastTexture) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (invslot == INVALID_INDEX)
|
||||
{
|
||||
inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (inventory_slot == INVALID_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = m_inv.GetItem(invslot);
|
||||
item = m_inv.GetItem(inventory_slot);
|
||||
|
||||
if(item && item->GetItem())
|
||||
{
|
||||
if (item && item->GetItem()) {
|
||||
return item->GetItem()->ID;
|
||||
}
|
||||
|
||||
@ -2904,7 +2902,7 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const
|
||||
if (material_slot > EQEmu::textures::LastTexture)
|
||||
return 0;
|
||||
|
||||
const EQEmu::ItemData *item = database.GetItem(GetEquipment(material_slot));
|
||||
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
if(item != nullptr)
|
||||
return ((m_pp.item_tint.Slot[material_slot].UseTint) ? m_pp.item_tint.Slot[material_slot].Color : item->Color);
|
||||
|
||||
|
||||
@ -1413,7 +1413,7 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
|
||||
luabind::adl::index_proxy<luabind::adl::object> cur = table["name"];
|
||||
LuaCreateNPCParseString(name, 64, "_");
|
||||
LuaCreateNPCParseString(lastname, 64, "");
|
||||
LuaCreateNPCParse(cur_hp, int32, 30);
|
||||
LuaCreateNPCParse(current_hp, int32, 30);
|
||||
LuaCreateNPCParse(max_hp, int32, 30);
|
||||
LuaCreateNPCParse(size, float, 6.0f);
|
||||
LuaCreateNPCParse(runspeed, float, 1.25f);
|
||||
|
||||
@ -859,14 +859,14 @@ int32 Merc::CalcMaxHP() {
|
||||
|
||||
max_hp += max_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f);
|
||||
|
||||
if (cur_hp > max_hp)
|
||||
cur_hp = max_hp;
|
||||
if (current_hp > max_hp)
|
||||
current_hp = max_hp;
|
||||
|
||||
int hp_perc_cap = spellbonuses.HPPercCap[0];
|
||||
if(hp_perc_cap) {
|
||||
int curHP_cap = (max_hp * hp_perc_cap) / 100;
|
||||
if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1]))
|
||||
cur_hp = curHP_cap;
|
||||
if (current_hp > curHP_cap || (spellbonuses.HPPercCap[1] && current_hp > spellbonuses.HPPercCap[1]))
|
||||
current_hp = curHP_cap;
|
||||
}
|
||||
|
||||
return max_hp;
|
||||
@ -4949,7 +4949,7 @@ void Merc::ScaleStats(int scalepercent, bool setmax) {
|
||||
max_hp = (int)((float)base_hp * scalerate);
|
||||
base_hp = max_hp;
|
||||
if (setmax)
|
||||
cur_hp = max_hp;
|
||||
current_hp = max_hp;
|
||||
}
|
||||
|
||||
if (base_mana)
|
||||
|
||||
654
zone/mob.cpp
654
zone/mob.cpp
@ -140,7 +140,7 @@ Mob::Mob(
|
||||
if (in_lastname) {
|
||||
strn0cpy(lastname, in_lastname, 64);
|
||||
}
|
||||
cur_hp = in_cur_hp;
|
||||
current_hp = in_cur_hp;
|
||||
max_hp = in_max_hp;
|
||||
base_hp = in_max_hp;
|
||||
gender = in_gender;
|
||||
@ -265,7 +265,7 @@ Mob::Mob(
|
||||
hidden = false;
|
||||
improved_hidden = false;
|
||||
invulnerable = false;
|
||||
IsFullHP = (cur_hp == max_hp);
|
||||
IsFullHP = (current_hp == max_hp);
|
||||
qglobal = 0;
|
||||
spawned = false;
|
||||
rare_spawn = false;
|
||||
@ -935,77 +935,76 @@ uint8 Mob::GetArchetype() const {
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::CreateSpawnPacket(EQApplicationPacket* app, Mob* ForWho) {
|
||||
void Mob::CreateSpawnPacket(EQApplicationPacket *app, Mob *ForWho)
|
||||
{
|
||||
app->SetOpcode(OP_NewSpawn);
|
||||
app->size = sizeof(NewSpawn_Struct);
|
||||
app->size = sizeof(NewSpawn_Struct);
|
||||
app->pBuffer = new uchar[app->size];
|
||||
memset(app->pBuffer, 0, app->size);
|
||||
NewSpawn_Struct* ns = (NewSpawn_Struct*)app->pBuffer;
|
||||
NewSpawn_Struct *ns = (NewSpawn_Struct *) app->pBuffer;
|
||||
FillSpawnStruct(ns, ForWho);
|
||||
|
||||
if(RuleB(NPC, UseClassAsLastName) && strlen(ns->spawn.lastName) == 0)
|
||||
{
|
||||
switch(ns->spawn.class_)
|
||||
{
|
||||
case TRIBUTE_MASTER:
|
||||
strcpy(ns->spawn.lastName, "Tribute Master");
|
||||
break;
|
||||
case ADVENTURERECRUITER:
|
||||
strcpy(ns->spawn.lastName, "Adventure Recruiter");
|
||||
break;
|
||||
case BANKER:
|
||||
strcpy(ns->spawn.lastName, "Banker");
|
||||
break;
|
||||
case ADVENTUREMERCHANT:
|
||||
strcpy(ns->spawn.lastName,"Adventure Merchant");
|
||||
break;
|
||||
case WARRIORGM:
|
||||
strcpy(ns->spawn.lastName, "GM Warrior");
|
||||
break;
|
||||
case PALADINGM:
|
||||
strcpy(ns->spawn.lastName, "GM Paladin");
|
||||
break;
|
||||
case RANGERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Ranger");
|
||||
break;
|
||||
case SHADOWKNIGHTGM:
|
||||
strcpy(ns->spawn.lastName, "GM Shadowknight");
|
||||
break;
|
||||
case DRUIDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Druid");
|
||||
break;
|
||||
case BARDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Bard");
|
||||
break;
|
||||
case ROGUEGM:
|
||||
strcpy(ns->spawn.lastName, "GM Rogue");
|
||||
break;
|
||||
case SHAMANGM:
|
||||
strcpy(ns->spawn.lastName, "GM Shaman");
|
||||
break;
|
||||
case NECROMANCERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Necromancer");
|
||||
break;
|
||||
case WIZARDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Wizard");
|
||||
break;
|
||||
case MAGICIANGM:
|
||||
strcpy(ns->spawn.lastName, "GM Magician");
|
||||
break;
|
||||
case ENCHANTERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Enchanter");
|
||||
break;
|
||||
case BEASTLORDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Beastlord");
|
||||
break;
|
||||
case BERSERKERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Berserker");
|
||||
break;
|
||||
case MERCERNARY_MASTER:
|
||||
strcpy(ns->spawn.lastName, "Mercenary Recruiter");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (RuleB(NPC, UseClassAsLastName) && strlen(ns->spawn.lastName) == 0) {
|
||||
switch (ns->spawn.class_) {
|
||||
case TRIBUTE_MASTER:
|
||||
strcpy(ns->spawn.lastName, "Tribute Master");
|
||||
break;
|
||||
case ADVENTURERECRUITER:
|
||||
strcpy(ns->spawn.lastName, "Adventure Recruiter");
|
||||
break;
|
||||
case BANKER:
|
||||
strcpy(ns->spawn.lastName, "Banker");
|
||||
break;
|
||||
case ADVENTUREMERCHANT:
|
||||
strcpy(ns->spawn.lastName, "Adventure Merchant");
|
||||
break;
|
||||
case WARRIORGM:
|
||||
strcpy(ns->spawn.lastName, "GM Warrior");
|
||||
break;
|
||||
case PALADINGM:
|
||||
strcpy(ns->spawn.lastName, "GM Paladin");
|
||||
break;
|
||||
case RANGERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Ranger");
|
||||
break;
|
||||
case SHADOWKNIGHTGM:
|
||||
strcpy(ns->spawn.lastName, "GM Shadowknight");
|
||||
break;
|
||||
case DRUIDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Druid");
|
||||
break;
|
||||
case BARDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Bard");
|
||||
break;
|
||||
case ROGUEGM:
|
||||
strcpy(ns->spawn.lastName, "GM Rogue");
|
||||
break;
|
||||
case SHAMANGM:
|
||||
strcpy(ns->spawn.lastName, "GM Shaman");
|
||||
break;
|
||||
case NECROMANCERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Necromancer");
|
||||
break;
|
||||
case WIZARDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Wizard");
|
||||
break;
|
||||
case MAGICIANGM:
|
||||
strcpy(ns->spawn.lastName, "GM Magician");
|
||||
break;
|
||||
case ENCHANTERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Enchanter");
|
||||
break;
|
||||
case BEASTLORDGM:
|
||||
strcpy(ns->spawn.lastName, "GM Beastlord");
|
||||
break;
|
||||
case BERSERKERGM:
|
||||
strcpy(ns->spawn.lastName, "GM Berserker");
|
||||
break;
|
||||
case MERCERNARY_MASTER:
|
||||
strcpy(ns->spawn.lastName, "Mercenary Recruiter");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1269,7 +1268,7 @@ void Mob::CreateDespawnPacket(EQApplicationPacket* app, bool Decay)
|
||||
|
||||
void Mob::CreateHPPacket(EQApplicationPacket* app)
|
||||
{
|
||||
this->IsFullHP=(cur_hp>=max_hp);
|
||||
this->IsFullHP=(current_hp>=max_hp);
|
||||
app->SetOpcode(OP_MobHealth);
|
||||
app->size = sizeof(SpawnHPUpdate_Struct2);
|
||||
app->pBuffer = new uchar[app->size];
|
||||
@ -1312,7 +1311,7 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
* If our HP is different from last HP update call - let's update selves
|
||||
*/
|
||||
if (IsClient()) {
|
||||
if (cur_hp != last_hp || force_update_all) {
|
||||
if (current_hp != last_hp || force_update_all) {
|
||||
|
||||
/**
|
||||
* This is to prevent excessive packet sending under trains/fast combat
|
||||
@ -1321,17 +1320,16 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
Log(Logs::General, Logs::HP_Update,
|
||||
"Mob::SendHPUpdate :: Update HP of self (%s) HP: %i last: %i skip_self: %s",
|
||||
this->GetCleanName(),
|
||||
cur_hp,
|
||||
current_hp,
|
||||
last_hp,
|
||||
(skip_self ? "true" : "false")
|
||||
);
|
||||
|
||||
if (!skip_self || this->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||
auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
|
||||
auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
|
||||
auto *hp_packet_client = (SpawnHPUpdate_Struct *) client_packet->pBuffer;
|
||||
|
||||
SpawnHPUpdate_Struct *hp_packet_client = (SpawnHPUpdate_Struct *) client_packet->pBuffer;
|
||||
|
||||
hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
|
||||
hp_packet_client->cur_hp = static_cast<uint32>(CastToClient()->GetHP() - itembonuses.HP);
|
||||
hp_packet_client->spawn_id = GetID();
|
||||
hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
|
||||
|
||||
@ -1345,12 +1343,12 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
/**
|
||||
* Used to check if HP has changed to update self next round
|
||||
*/
|
||||
last_hp = cur_hp;
|
||||
last_hp = current_hp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8 current_hp_percent = (max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp));
|
||||
int8 current_hp_percent = static_cast<int8>(max_hp == 0 ? 0 : static_cast<int>(current_hp * 100 / max_hp));
|
||||
|
||||
Log(Logs::General,
|
||||
Logs::HP_Update,
|
||||
@ -1680,129 +1678,171 @@ void Mob::GMMove(float x, float y, float z, float heading, bool SendUpdate) {
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture, uint8 in_helmtexture, uint8 in_haircolor, uint8 in_beardcolor, uint8 in_eyecolor1, uint8 in_eyecolor2, uint8 in_hairstyle, uint8 in_luclinface, uint8 in_beard, uint8 in_aa_title, uint32 in_drakkin_heritage, uint32 in_drakkin_tattoo, uint32 in_drakkin_details, float in_size) {
|
||||
void Mob::SendIllusionPacket(
|
||||
uint16 in_race,
|
||||
uint8 in_gender,
|
||||
uint8 in_texture,
|
||||
uint8 in_helmtexture,
|
||||
uint8 in_haircolor,
|
||||
uint8 in_beardcolor,
|
||||
uint8 in_eyecolor1,
|
||||
uint8 in_eyecolor2,
|
||||
uint8 in_hairstyle,
|
||||
uint8 in_luclinface,
|
||||
uint8 in_beard,
|
||||
uint8 in_aa_title,
|
||||
uint32 in_drakkin_heritage,
|
||||
uint32 in_drakkin_tattoo,
|
||||
uint32 in_drakkin_details,
|
||||
float in_size
|
||||
)
|
||||
{
|
||||
|
||||
uint16 BaseRace = GetBaseRace();
|
||||
|
||||
if (in_race == 0)
|
||||
{
|
||||
if (in_race == 0) {
|
||||
race = BaseRace;
|
||||
if (in_gender == 0xFF)
|
||||
if (in_gender == 0xFF) {
|
||||
gender = GetBaseGender();
|
||||
else
|
||||
}
|
||||
else {
|
||||
gender = in_gender;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
race = in_race;
|
||||
if (in_gender == 0xFF)
|
||||
if (in_gender == 0xFF) {
|
||||
gender = GetDefaultGender(race, gender);
|
||||
else
|
||||
}
|
||||
else {
|
||||
gender = in_gender;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_texture == 0xFF)
|
||||
{
|
||||
if (IsPlayerRace(in_race))
|
||||
if (in_texture == 0xFF) {
|
||||
if (IsPlayerRace(in_race)) {
|
||||
texture = 0xFF;
|
||||
else
|
||||
}
|
||||
else {
|
||||
texture = GetTexture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
texture = in_texture;
|
||||
}
|
||||
|
||||
if (in_helmtexture == 0xFF)
|
||||
{
|
||||
if (IsPlayerRace(in_race))
|
||||
if (in_helmtexture == 0xFF) {
|
||||
if (IsPlayerRace(in_race)) {
|
||||
helmtexture = 0xFF;
|
||||
else if (in_texture != 0xFF)
|
||||
}
|
||||
else if (in_texture != 0xFF) {
|
||||
helmtexture = in_texture;
|
||||
else
|
||||
}
|
||||
else {
|
||||
helmtexture = GetHelmTexture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
helmtexture = in_helmtexture;
|
||||
}
|
||||
|
||||
if (in_haircolor == 0xFF)
|
||||
if (in_haircolor == 0xFF) {
|
||||
haircolor = GetHairColor();
|
||||
else
|
||||
}
|
||||
else {
|
||||
haircolor = in_haircolor;
|
||||
}
|
||||
|
||||
if (in_beardcolor == 0xFF)
|
||||
if (in_beardcolor == 0xFF) {
|
||||
beardcolor = GetBeardColor();
|
||||
else
|
||||
}
|
||||
else {
|
||||
beardcolor = in_beardcolor;
|
||||
}
|
||||
|
||||
if (in_eyecolor1 == 0xFF)
|
||||
if (in_eyecolor1 == 0xFF) {
|
||||
eyecolor1 = GetEyeColor1();
|
||||
else
|
||||
}
|
||||
else {
|
||||
eyecolor1 = in_eyecolor1;
|
||||
}
|
||||
|
||||
if (in_eyecolor2 == 0xFF)
|
||||
if (in_eyecolor2 == 0xFF) {
|
||||
eyecolor2 = GetEyeColor2();
|
||||
else
|
||||
}
|
||||
else {
|
||||
eyecolor2 = in_eyecolor2;
|
||||
}
|
||||
|
||||
if (in_hairstyle == 0xFF)
|
||||
if (in_hairstyle == 0xFF) {
|
||||
hairstyle = GetHairStyle();
|
||||
else
|
||||
}
|
||||
else {
|
||||
hairstyle = in_hairstyle;
|
||||
}
|
||||
|
||||
if (in_luclinface == 0xFF)
|
||||
if (in_luclinface == 0xFF) {
|
||||
luclinface = GetLuclinFace();
|
||||
else
|
||||
}
|
||||
else {
|
||||
luclinface = in_luclinface;
|
||||
}
|
||||
|
||||
if (in_beard == 0xFF)
|
||||
if (in_beard == 0xFF) {
|
||||
beard = GetBeard();
|
||||
else
|
||||
}
|
||||
else {
|
||||
beard = in_beard;
|
||||
}
|
||||
|
||||
aa_title = in_aa_title;
|
||||
|
||||
if (in_drakkin_heritage == 0xFFFFFFFF)
|
||||
if (in_drakkin_heritage == 0xFFFFFFFF) {
|
||||
drakkin_heritage = GetDrakkinHeritage();
|
||||
else
|
||||
}
|
||||
else {
|
||||
drakkin_heritage = in_drakkin_heritage;
|
||||
}
|
||||
|
||||
if (in_drakkin_tattoo == 0xFFFFFFFF)
|
||||
if (in_drakkin_tattoo == 0xFFFFFFFF) {
|
||||
drakkin_tattoo = GetDrakkinTattoo();
|
||||
else
|
||||
}
|
||||
else {
|
||||
drakkin_tattoo = in_drakkin_tattoo;
|
||||
}
|
||||
|
||||
if (in_drakkin_details == 0xFFFFFFFF)
|
||||
if (in_drakkin_details == 0xFFFFFFFF) {
|
||||
drakkin_details = GetDrakkinDetails();
|
||||
else
|
||||
}
|
||||
else {
|
||||
drakkin_details = in_drakkin_details;
|
||||
}
|
||||
|
||||
if (in_size <= 0.0f)
|
||||
if (in_size <= 0.0f) {
|
||||
size = GetSize();
|
||||
else
|
||||
}
|
||||
else {
|
||||
size = in_size;
|
||||
}
|
||||
|
||||
// Reset features to Base from the Player Profile
|
||||
if (IsClient() && in_race == 0)
|
||||
{
|
||||
race = CastToClient()->GetBaseRace();
|
||||
gender = CastToClient()->GetBaseGender();
|
||||
texture = 0xFF;
|
||||
helmtexture = 0xFF;
|
||||
haircolor = CastToClient()->GetBaseHairColor();
|
||||
beardcolor = CastToClient()->GetBaseBeardColor();
|
||||
eyecolor1 = CastToClient()->GetBaseEyeColor();
|
||||
eyecolor2 = CastToClient()->GetBaseEyeColor();
|
||||
hairstyle = CastToClient()->GetBaseHairStyle();
|
||||
luclinface = CastToClient()->GetBaseFace();
|
||||
beard = CastToClient()->GetBaseBeard();
|
||||
aa_title = 0xFF;
|
||||
if (IsClient() && in_race == 0) {
|
||||
race = CastToClient()->GetBaseRace();
|
||||
gender = CastToClient()->GetBaseGender();
|
||||
texture = 0xFF;
|
||||
helmtexture = 0xFF;
|
||||
haircolor = CastToClient()->GetBaseHairColor();
|
||||
beardcolor = CastToClient()->GetBaseBeardColor();
|
||||
eyecolor1 = CastToClient()->GetBaseEyeColor();
|
||||
eyecolor2 = CastToClient()->GetBaseEyeColor();
|
||||
hairstyle = CastToClient()->GetBaseHairStyle();
|
||||
luclinface = CastToClient()->GetBaseFace();
|
||||
beard = CastToClient()->GetBaseBeard();
|
||||
aa_title = 0xFF;
|
||||
drakkin_heritage = CastToClient()->GetBaseHeritage();
|
||||
drakkin_tattoo = CastToClient()->GetBaseTattoo();
|
||||
drakkin_details = CastToClient()->GetBaseDetails();
|
||||
switch(race){
|
||||
drakkin_tattoo = CastToClient()->GetBaseTattoo();
|
||||
drakkin_details = CastToClient()->GetBaseDetails();
|
||||
switch (race) {
|
||||
case OGRE:
|
||||
size = 9;
|
||||
break;
|
||||
@ -1832,25 +1872,25 @@ void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture,
|
||||
}
|
||||
}
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct));
|
||||
Illusion_Struct* is = (Illusion_Struct*) outapp->pBuffer;
|
||||
auto outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct));
|
||||
Illusion_Struct *is = (Illusion_Struct *) outapp->pBuffer;
|
||||
is->spawnid = GetID();
|
||||
strcpy(is->charname, GetCleanName());
|
||||
is->race = race;
|
||||
is->gender = gender;
|
||||
is->texture = texture;
|
||||
is->helmtexture = helmtexture;
|
||||
is->haircolor = haircolor;
|
||||
is->beardcolor = beardcolor;
|
||||
is->beard = beard;
|
||||
is->eyecolor1 = eyecolor1;
|
||||
is->eyecolor2 = eyecolor2;
|
||||
is->hairstyle = hairstyle;
|
||||
is->face = luclinface;
|
||||
is->race = race;
|
||||
is->gender = gender;
|
||||
is->texture = texture;
|
||||
is->helmtexture = helmtexture;
|
||||
is->haircolor = haircolor;
|
||||
is->beardcolor = beardcolor;
|
||||
is->beard = beard;
|
||||
is->eyecolor1 = eyecolor1;
|
||||
is->eyecolor2 = eyecolor2;
|
||||
is->hairstyle = hairstyle;
|
||||
is->face = luclinface;
|
||||
is->drakkin_heritage = drakkin_heritage;
|
||||
is->drakkin_tattoo = drakkin_tattoo;
|
||||
is->drakkin_details = drakkin_details;
|
||||
is->size = size;
|
||||
is->drakkin_tattoo = drakkin_tattoo;
|
||||
is->drakkin_details = drakkin_details;
|
||||
is->size = size;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
@ -1858,8 +1898,23 @@ void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture,
|
||||
/* Refresh armor and tints after send illusion packet */
|
||||
this->SendArmorAppearance();
|
||||
|
||||
Log(Logs::Detail, Logs::Spells, "Illusion: Race = %i, Gender = %i, Texture = %i, HelmTexture = %i, HairColor = %i, BeardColor = %i, EyeColor1 = %i, EyeColor2 = %i, HairStyle = %i, Face = %i, DrakkinHeritage = %i, DrakkinTattoo = %i, DrakkinDetails = %i, Size = %f",
|
||||
race, gender, texture, helmtexture, haircolor, beardcolor, eyecolor1, eyecolor2, hairstyle, luclinface, drakkin_heritage, drakkin_tattoo, drakkin_details, size);
|
||||
Log(Logs::Detail,
|
||||
Logs::Spells,
|
||||
"Illusion: Race = %i, Gender = %i, Texture = %i, HelmTexture = %i, HairColor = %i, BeardColor = %i, EyeColor1 = %i, EyeColor2 = %i, HairStyle = %i, Face = %i, DrakkinHeritage = %i, DrakkinTattoo = %i, DrakkinDetails = %i, Size = %f",
|
||||
race,
|
||||
gender,
|
||||
texture,
|
||||
helmtexture,
|
||||
haircolor,
|
||||
beardcolor,
|
||||
eyecolor1,
|
||||
eyecolor2,
|
||||
hairstyle,
|
||||
luclinface,
|
||||
drakkin_heritage,
|
||||
drakkin_tattoo,
|
||||
drakkin_details,
|
||||
size);
|
||||
}
|
||||
|
||||
bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables)
|
||||
@ -2810,275 +2865,11 @@ uint32 Mob::RandomTimer(int min,int max) {
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32 NPC::GetEquipment(uint8 material_slot) const
|
||||
{
|
||||
if(material_slot > 8)
|
||||
return 0;
|
||||
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (invslot == INVALID_INDEX)
|
||||
return 0;
|
||||
return equipment[invslot];
|
||||
}
|
||||
|
||||
void Mob::SendArmorAppearance(Client *one_client)
|
||||
{
|
||||
// one_client of 0 means sent to all clients
|
||||
//
|
||||
// Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the
|
||||
// armor being worn and its mats, the client doesn't update the display
|
||||
// on arrival of these packets reliably.
|
||||
//
|
||||
// Send Wear changes if mob is a PC race and item is an armor slot.
|
||||
// The other packets work for primary/secondary.
|
||||
|
||||
if (IsPlayerRace(race))
|
||||
{
|
||||
if (!IsClient())
|
||||
{
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
item = database.GetItem(GetEquipment(i));
|
||||
if (item != 0)
|
||||
{
|
||||
SendWearChange(i, one_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::SendWearChange(uint8 material_slot, Client *one_client)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer;
|
||||
|
||||
wc->spawn_id = GetID();
|
||||
wc->material = GetEquipmentMaterial(material_slot);
|
||||
wc->elite_material = IsEliteMaterialItem(material_slot);
|
||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||
|
||||
#ifdef BOTS
|
||||
if (IsBot()) {
|
||||
auto item_inst = CastToBot()->GetBotItem(EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot));
|
||||
if (item_inst)
|
||||
wc->color.Color = item_inst->GetColor();
|
||||
else
|
||||
wc->color.Color = 0;
|
||||
}
|
||||
else {
|
||||
wc->color.Color = GetEquipmentColor(material_slot);
|
||||
}
|
||||
#else
|
||||
wc->color.Color = GetEquipmentColor(material_slot);
|
||||
#endif
|
||||
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
if (!one_client)
|
||||
{
|
||||
entity_list.QueueClients(this, outapp);
|
||||
}
|
||||
else
|
||||
{
|
||||
one_client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model, uint32 elite_material, uint32 unknown06, uint32 unknown18)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer;
|
||||
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = texture;
|
||||
if (this->IsClient())
|
||||
wc->color.Color = GetEquipmentColor(slot);
|
||||
else
|
||||
wc->color.Color = this->GetArmorTint(slot);
|
||||
wc->wear_slot_id = slot;
|
||||
|
||||
wc->unknown06 = unknown06;
|
||||
wc->elite_material = elite_material;
|
||||
wc->hero_forge_model = hero_forge_model;
|
||||
wc->unknown18 = unknown18;
|
||||
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint)
|
||||
{
|
||||
uint32 color;
|
||||
color = (red_tint & 0xFF) << 16;
|
||||
color |= (green_tint & 0xFF) << 8;
|
||||
color |= (blue_tint & 0xFF);
|
||||
color |= (color) ? (0xFF << 24) : 0;
|
||||
armor_tint.Slot[material_slot].Color = color;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer;
|
||||
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = GetEquipmentMaterial(material_slot);
|
||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||
wc->color.Color = color;
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model)
|
||||
{
|
||||
armor_tint.Slot[material_slot].Color = color;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer;
|
||||
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = texture;
|
||||
wc->hero_forge_model = hero_forge_model;
|
||||
wc->color.Color = color;
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
int32 Mob::GetEquipmentMaterial(uint8 material_slot) const
|
||||
{
|
||||
uint32 equipmaterial = 0;
|
||||
int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
|
||||
if (item != 0)
|
||||
{
|
||||
// For primary and secondary we need the model, not the material
|
||||
if (material_slot == EQEmu::textures::weaponPrimary || material_slot == EQEmu::textures::weaponSecondary)
|
||||
{
|
||||
if (this->IsClient())
|
||||
{
|
||||
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (invslot == INVALID_INDEX)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const EQEmu::ItemInstance* inst = CastToClient()->m_inv[invslot];
|
||||
if (inst)
|
||||
{
|
||||
if (inst->GetOrnamentationAug(ornamentationAugtype))
|
||||
{
|
||||
item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
||||
if (item && strlen(item->IDFile) > 2)
|
||||
{
|
||||
equipmaterial = atoi(&item->IDFile[2]);
|
||||
}
|
||||
}
|
||||
else if (inst->GetOrnamentationIDFile())
|
||||
{
|
||||
equipmaterial = inst->GetOrnamentationIDFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (equipmaterial == 0 && strlen(item->IDFile) > 2)
|
||||
{
|
||||
equipmaterial = atoi(&item->IDFile[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
equipmaterial = item->Material;
|
||||
}
|
||||
}
|
||||
|
||||
return equipmaterial;
|
||||
}
|
||||
|
||||
int32 Mob::GetHerosForgeModel(uint8 material_slot) const
|
||||
{
|
||||
uint32 HeroModel = 0;
|
||||
if (material_slot >= 0 && material_slot < EQEmu::textures::weaponPrimary)
|
||||
{
|
||||
uint32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
|
||||
if (item != 0 && invslot != INVALID_INDEX)
|
||||
{
|
||||
if (IsClient())
|
||||
{
|
||||
const EQEmu::ItemInstance* inst = CastToClient()->m_inv[invslot];
|
||||
if (inst)
|
||||
{
|
||||
if (inst->GetOrnamentationAug(ornamentationAugtype))
|
||||
{
|
||||
item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
||||
HeroModel = item->HerosForgeModel;
|
||||
}
|
||||
else if (inst->GetOrnamentHeroModel())
|
||||
{
|
||||
HeroModel = inst->GetOrnamentHeroModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HeroModel == 0)
|
||||
{
|
||||
HeroModel = item->HerosForgeModel;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNPC())
|
||||
{
|
||||
HeroModel = CastToNPC()->GetHeroForgeModel();
|
||||
// Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots
|
||||
if (HeroModel > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 && material_slot != 5)
|
||||
{
|
||||
HeroModel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-Convert Hero Model to match the slot
|
||||
// Otherwise, use the exact Model if model is > 999
|
||||
// Robes for example are 11607 to 12107 in RoF
|
||||
if (HeroModel > 0 && HeroModel < 1000)
|
||||
{
|
||||
HeroModel *= 100;
|
||||
HeroModel += material_slot;
|
||||
}
|
||||
|
||||
return HeroModel;
|
||||
}
|
||||
|
||||
uint32 Mob::GetEquipmentColor(uint8 material_slot) const
|
||||
{
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
|
||||
if (armor_tint.Slot[material_slot].Color)
|
||||
{
|
||||
return armor_tint.Slot[material_slot].Color;
|
||||
}
|
||||
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
if (item != 0)
|
||||
return item->Color;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 Mob::IsEliteMaterialItem(uint8 material_slot) const
|
||||
{
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
|
||||
item = database.GetItem(GetEquipment(material_slot));
|
||||
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
if(item != 0)
|
||||
{
|
||||
return item->EliteMaterial;
|
||||
@ -3090,26 +2881,31 @@ uint32 Mob::IsEliteMaterialItem(uint8 material_slot) const
|
||||
// works just like a printf
|
||||
void Mob::Say(const char *format, ...)
|
||||
{
|
||||
char buf[1000];
|
||||
char buf[1000];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, 1000, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
Mob* talker = this;
|
||||
if(spellbonuses.VoiceGraft != 0) {
|
||||
if(spellbonuses.VoiceGraft == GetPetID())
|
||||
Mob *talker = this;
|
||||
if (spellbonuses.VoiceGraft != 0) {
|
||||
if (spellbonuses.VoiceGraft == GetPetID()) {
|
||||
talker = entity_list.GetMob(spellbonuses.VoiceGraft);
|
||||
else
|
||||
}
|
||||
else {
|
||||
spellbonuses.VoiceGraft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!talker)
|
||||
if (!talker) {
|
||||
talker = this;
|
||||
}
|
||||
|
||||
entity_list.MessageClose_StringID(talker, false, 200, 10,
|
||||
GENERIC_SAY, GetCleanName(), buf);
|
||||
entity_list.MessageClose_StringID(
|
||||
talker, false, 200, 10,
|
||||
GENERIC_SAY, GetCleanName(), buf
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
174
zone/mob.h
174
zone/mob.h
@ -107,58 +107,59 @@ public:
|
||||
AuraMgr() : count(0) { }
|
||||
};
|
||||
|
||||
Mob(const char* in_name,
|
||||
const char* in_lastname,
|
||||
int32 in_cur_hp,
|
||||
int32 in_max_hp,
|
||||
uint8 in_gender,
|
||||
uint16 in_race,
|
||||
uint8 in_class,
|
||||
bodyType in_bodytype,
|
||||
uint8 in_deity,
|
||||
uint8 in_level,
|
||||
uint32 in_npctype_id,
|
||||
float in_size,
|
||||
float in_runspeed,
|
||||
const glm::vec4& position,
|
||||
uint8 in_light,
|
||||
uint8 in_texture,
|
||||
uint8 in_helmtexture,
|
||||
uint16 in_ac,
|
||||
uint16 in_atk,
|
||||
uint16 in_str,
|
||||
uint16 in_sta,
|
||||
uint16 in_dex,
|
||||
uint16 in_agi,
|
||||
uint16 in_int,
|
||||
uint16 in_wis,
|
||||
uint16 in_cha,
|
||||
uint8 in_haircolor,
|
||||
uint8 in_beardcolor,
|
||||
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
|
||||
uint8 in_eyecolor2,
|
||||
uint8 in_hairstyle,
|
||||
uint8 in_luclinface,
|
||||
uint8 in_beard,
|
||||
uint32 in_drakkin_heritage,
|
||||
uint32 in_drakkin_tattoo,
|
||||
uint32 in_drakkin_details,
|
||||
EQEmu::TintProfile in_armor_tint,
|
||||
uint8 in_aa_title,
|
||||
uint8 in_see_invis, // see through invis
|
||||
uint8 in_see_invis_undead, // see through invis vs. undead
|
||||
uint8 in_see_hide,
|
||||
uint8 in_see_improved_hide,
|
||||
int32 in_hp_regen,
|
||||
int32 in_mana_regen,
|
||||
uint8 in_qglobal,
|
||||
uint8 in_maxlevel,
|
||||
uint32 in_scalerate,
|
||||
uint8 in_armtexture,
|
||||
uint8 in_bracertexture,
|
||||
uint8 in_handtexture,
|
||||
uint8 in_legtexture,
|
||||
uint8 in_feettexture
|
||||
Mob(
|
||||
const char *in_name,
|
||||
const char *in_lastname,
|
||||
int32 in_cur_hp,
|
||||
int32 in_max_hp,
|
||||
uint8 in_gender,
|
||||
uint16 in_race,
|
||||
uint8 in_class,
|
||||
bodyType in_bodytype,
|
||||
uint8 in_deity,
|
||||
uint8 in_level,
|
||||
uint32 in_npctype_id,
|
||||
float in_size,
|
||||
float in_runspeed,
|
||||
const glm::vec4 &position,
|
||||
uint8 in_light,
|
||||
uint8 in_texture,
|
||||
uint8 in_helmtexture,
|
||||
uint16 in_ac,
|
||||
uint16 in_atk,
|
||||
uint16 in_str,
|
||||
uint16 in_sta,
|
||||
uint16 in_dex,
|
||||
uint16 in_agi,
|
||||
uint16 in_int,
|
||||
uint16 in_wis,
|
||||
uint16 in_cha,
|
||||
uint8 in_haircolor,
|
||||
uint8 in_beardcolor,
|
||||
uint8 in_eyecolor1, // the eyecolors always seem to be the same, maybe left and right eye?
|
||||
uint8 in_eyecolor2,
|
||||
uint8 in_hairstyle,
|
||||
uint8 in_luclinface,
|
||||
uint8 in_beard,
|
||||
uint32 in_drakkin_heritage,
|
||||
uint32 in_drakkin_tattoo,
|
||||
uint32 in_drakkin_details,
|
||||
EQEmu::TintProfile in_armor_tint,
|
||||
uint8 in_aa_title,
|
||||
uint8 in_see_invis, // see through invis
|
||||
uint8 in_see_invis_undead, // see through invis vs. undead
|
||||
uint8 in_see_hide,
|
||||
uint8 in_see_improved_hide,
|
||||
int32 in_hp_regen,
|
||||
int32 in_mana_regen,
|
||||
uint8 in_qglobal,
|
||||
uint8 in_maxlevel,
|
||||
uint32 in_scalerate,
|
||||
uint8 in_armtexture,
|
||||
uint8 in_bracertexture,
|
||||
uint8 in_handtexture,
|
||||
uint8 in_legtexture,
|
||||
uint8 in_feettexture
|
||||
);
|
||||
virtual ~Mob();
|
||||
|
||||
@ -237,30 +238,43 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
//Appearance
|
||||
void SendLevelAppearance();
|
||||
void SendStunAppearance();
|
||||
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5,
|
||||
Client *specific_target=nullptr);
|
||||
void SendTargetable(bool on, Client *specific_target = nullptr);
|
||||
virtual void SendArmorAppearance(Client *one_client = nullptr);
|
||||
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
|
||||
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0,
|
||||
uint32 unknown06 = 0, uint32 unknown18 = 0);
|
||||
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
|
||||
virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0);
|
||||
void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone);
|
||||
void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0,
|
||||
float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery);
|
||||
void ChangeSize(float in_size, bool bNoRestriction = false);
|
||||
inline uint8 SeeInvisible() const { return see_invis; }
|
||||
inline bool SeeInvisibleUndead() const { return see_invis_undead; }
|
||||
/**
|
||||
************************************************
|
||||
* Appearance
|
||||
************************************************
|
||||
*/
|
||||
|
||||
EQEmu::InternalTextureProfile mob_texture_profile = {};
|
||||
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
|
||||
EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt);
|
||||
|
||||
inline bool GetSeeInvisible(uint8 see_invis);
|
||||
inline bool SeeHide() const { return see_hide; }
|
||||
inline bool SeeImprovedHide() const { return see_improved_hide; }
|
||||
inline bool GetSeeInvisible(uint8 see_invis);
|
||||
bool IsInvisible(Mob* other = 0) const;
|
||||
inline bool SeeInvisibleUndead() const { return see_invis_undead; }
|
||||
inline uint8 SeeInvisible() const { return see_invis; }
|
||||
|
||||
int32 GetTextureProfileMaterial(uint8 material_slot) const;
|
||||
int32 GetTextureProfileColor(uint8 material_slot) const;
|
||||
int32 GetTextureProfileHeroForgeModel(uint8 material_slot) const;
|
||||
|
||||
virtual void SendArmorAppearance(Client *one_client = nullptr);
|
||||
virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0);
|
||||
virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr);
|
||||
virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);
|
||||
virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0);
|
||||
|
||||
void ChangeSize(float in_size, bool bNoRestriction = false);
|
||||
void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone);
|
||||
void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0, float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery);
|
||||
void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Client *specific_target=nullptr);
|
||||
void SendLevelAppearance();
|
||||
void SendStunAppearance();
|
||||
void SendTargetable(bool on, Client *specific_target = nullptr);
|
||||
void SetInvisible(uint8 state);
|
||||
EQEmu::skills::SkillType AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse = EQEmu::skills::Skill1HBlunt);
|
||||
void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0);
|
||||
|
||||
//Song
|
||||
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
|
||||
@ -410,7 +424,7 @@ public:
|
||||
bool CanFacestab() { return can_facestab; }
|
||||
void SetFacestab(bool val) { can_facestab = val; }
|
||||
virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { return 0; }
|
||||
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
||||
virtual uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const { return(0); }
|
||||
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
virtual int32 GetHerosForgeModel(uint8 material_slot) const;
|
||||
virtual uint32 GetEquipmentColor(uint8 material_slot) const;
|
||||
@ -420,12 +434,12 @@ public:
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) = 0;
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill,
|
||||
bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) = 0;
|
||||
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;}
|
||||
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) current_hp = max_hp; else current_hp = hp;}
|
||||
bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false);
|
||||
inline void SetOOCRegen(int32 newoocregen) {ooc_regen = newoocregen;}
|
||||
virtual void Heal();
|
||||
virtual void HealDamage(uint32 ammount, Mob* caster = nullptr, uint16 spell_id = SPELL_UNKNOWN);
|
||||
virtual void SetMaxHP() { cur_hp = max_hp; }
|
||||
virtual void SetMaxHP() { current_hp = max_hp; }
|
||||
virtual inline uint16 GetBaseRace() const { return base_race; }
|
||||
virtual inline uint8 GetBaseGender() const { return base_gender; }
|
||||
virtual inline uint16 GetDeity() const { return deity; }
|
||||
@ -471,8 +485,8 @@ public:
|
||||
inline Mob* GetTarget() const { return target; }
|
||||
virtual void SetTarget(Mob* mob);
|
||||
inline bool HasTargetReflection() const { return (target && target != this && target->target == this); }
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
|
||||
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp); }
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)current_hp/max_hp*100); }
|
||||
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(current_hp * 100 / max_hp); }
|
||||
inline int32 GetAC() const { return AC; }
|
||||
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
|
||||
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
@ -521,7 +535,7 @@ public:
|
||||
inline virtual int32 GetMaxCR() const { return 255; }
|
||||
inline virtual int32 GetMaxFR() const { return 255; }
|
||||
inline virtual int32 GetDelayDeath() const { return 0; }
|
||||
inline int32 GetHP() const { return cur_hp; }
|
||||
inline int32 GetHP() const { return current_hp; }
|
||||
inline int32 GetMaxHP() const { return max_hp; }
|
||||
virtual int32 CalcMaxHP();
|
||||
inline int32 GetMaxMana() const { return max_mana; }
|
||||
@ -1231,7 +1245,7 @@ protected:
|
||||
int targeted;
|
||||
bool findable;
|
||||
bool trackable;
|
||||
int32 cur_hp;
|
||||
int32 current_hp;
|
||||
int32 max_hp;
|
||||
int32 base_hp;
|
||||
int32 current_mana;
|
||||
|
||||
544
zone/mob_appearance.cpp
Normal file
544
zone/mob_appearance.cpp
Normal file
@ -0,0 +1,544 @@
|
||||
/**
|
||||
* EQEmulator: Everquest Server Emulator
|
||||
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
||||
* are required to give you total support for your newly bought product;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
#include "mob.h"
|
||||
#include "quest_parser_collection.h"
|
||||
#include "zonedb.h"
|
||||
|
||||
/**
|
||||
* Stores internal representation of mob texture by material slot
|
||||
*
|
||||
* @param material_slot
|
||||
* @param texture
|
||||
* @param color
|
||||
* @param hero_forge_model
|
||||
*/
|
||||
void Mob::SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model)
|
||||
{
|
||||
Log(Logs::Detail, Logs::MobAppearance,
|
||||
"Mob::SetMobTextureProfile [%s] material_slot: %u texture: %u color: %u hero_forge_model: %u",
|
||||
this->GetCleanName(),
|
||||
material_slot,
|
||||
texture,
|
||||
color,
|
||||
hero_forge_model
|
||||
);
|
||||
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
mob_texture_profile.Head.Material = texture;
|
||||
mob_texture_profile.Head.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Head.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorChest:
|
||||
mob_texture_profile.Chest.Material = texture;
|
||||
mob_texture_profile.Chest.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Chest.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorArms:
|
||||
mob_texture_profile.Arms.Material = texture;
|
||||
mob_texture_profile.Arms.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Arms.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorWrist:
|
||||
mob_texture_profile.Wrist.Material = texture;
|
||||
mob_texture_profile.Wrist.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Wrist.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorHands:
|
||||
mob_texture_profile.Hands.Material = texture;
|
||||
mob_texture_profile.Hands.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Hands.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorLegs:
|
||||
mob_texture_profile.Legs.Material = texture;
|
||||
mob_texture_profile.Legs.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Legs.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::armorFeet:
|
||||
mob_texture_profile.Feet.Material = texture;
|
||||
mob_texture_profile.Feet.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Feet.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
mob_texture_profile.Primary.Material = texture;
|
||||
mob_texture_profile.Primary.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Primary.Color = color;
|
||||
break;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
mob_texture_profile.Secondary.Material = texture;
|
||||
mob_texture_profile.Secondary.HerosForgeModel = hero_forge_model;
|
||||
mob_texture_profile.Secondary.Color = color;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns internal representation of mob texture by material
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetTextureProfileMaterial(uint8 material_slot) const
|
||||
{
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
return mob_texture_profile.Head.Material;
|
||||
case EQEmu::textures::armorChest:
|
||||
return mob_texture_profile.Chest.Material;
|
||||
case EQEmu::textures::armorArms:
|
||||
return mob_texture_profile.Arms.Material;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return mob_texture_profile.Wrist.Material;
|
||||
case EQEmu::textures::armorHands:
|
||||
return mob_texture_profile.Hands.Material;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return mob_texture_profile.Legs.Material;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return mob_texture_profile.Feet.Material;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return mob_texture_profile.Primary.Material;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return mob_texture_profile.Secondary.Material;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns internal representation of mob texture by color
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetTextureProfileColor(uint8 material_slot) const
|
||||
{
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
return mob_texture_profile.Head.Color;
|
||||
case EQEmu::textures::armorChest:
|
||||
return mob_texture_profile.Chest.Color;
|
||||
case EQEmu::textures::armorArms:
|
||||
return mob_texture_profile.Arms.Color;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return mob_texture_profile.Wrist.Color;
|
||||
case EQEmu::textures::armorHands:
|
||||
return mob_texture_profile.Hands.Color;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return mob_texture_profile.Legs.Color;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return mob_texture_profile.Feet.Color;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return mob_texture_profile.Primary.Color;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return mob_texture_profile.Secondary.Color;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns internal representation of mob texture by HerosForgeModel
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetTextureProfileHeroForgeModel(uint8 material_slot) const
|
||||
{
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
return mob_texture_profile.Head.HerosForgeModel;
|
||||
case EQEmu::textures::armorChest:
|
||||
return mob_texture_profile.Chest.HerosForgeModel;
|
||||
case EQEmu::textures::armorArms:
|
||||
return mob_texture_profile.Arms.HerosForgeModel;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return mob_texture_profile.Wrist.HerosForgeModel;
|
||||
case EQEmu::textures::armorHands:
|
||||
return mob_texture_profile.Hands.HerosForgeModel;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return mob_texture_profile.Legs.HerosForgeModel;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return mob_texture_profile.Feet.HerosForgeModel;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return mob_texture_profile.Primary.HerosForgeModel;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return mob_texture_profile.Secondary.HerosForgeModel;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the material or texture for a slot (leather / plate etc.)
|
||||
*
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetEquipmentMaterial(uint8 material_slot) const
|
||||
{
|
||||
uint32 equipment_material = 0;
|
||||
int32 ornamentation_augment_type = RuleI(Character, OrnamentationAugmentType);
|
||||
|
||||
int32 texture_profile_material = GetTextureProfileMaterial(material_slot);
|
||||
|
||||
Log(Logs::Detail, Logs::MobAppearance,
|
||||
"Mob::GetEquipmentMaterial [%s] material_slot: %u texture_profile_material: %i",
|
||||
this->clean_name,
|
||||
material_slot,
|
||||
texture_profile_material
|
||||
);
|
||||
|
||||
if (texture_profile_material > 0) {
|
||||
return texture_profile_material;
|
||||
}
|
||||
|
||||
auto item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
|
||||
if (item != nullptr) {
|
||||
|
||||
/**
|
||||
* Handle primary / secondary texture
|
||||
*/
|
||||
bool is_primary_or_secondary_weapon =
|
||||
material_slot == EQEmu::textures::weaponPrimary ||
|
||||
material_slot == EQEmu::textures::weaponSecondary;
|
||||
|
||||
if (is_primary_or_secondary_weapon) {
|
||||
if (this->IsClient()) {
|
||||
|
||||
int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (inventory_slot == INVALID_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const EQEmu::ItemInstance *item_instance = CastToClient()->m_inv[inventory_slot];
|
||||
if (item_instance) {
|
||||
if (item_instance->GetOrnamentationAug(ornamentation_augment_type)) {
|
||||
item = item_instance->GetOrnamentationAug(ornamentation_augment_type)->GetItem();
|
||||
if (item && strlen(item->IDFile) > 2) {
|
||||
equipment_material = atoi(&item->IDFile[2]);
|
||||
}
|
||||
}
|
||||
else if (item_instance->GetOrnamentationIDFile()) {
|
||||
equipment_material = item_instance->GetOrnamentationIDFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (equipment_material == 0 && strlen(item->IDFile) > 2) {
|
||||
equipment_material = atoi(&item->IDFile[2]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
equipment_material = item->Material;
|
||||
}
|
||||
}
|
||||
|
||||
return equipment_material;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
uint32 Mob::GetEquipmentColor(uint8 material_slot) const
|
||||
{
|
||||
const EQEmu::ItemData *item = nullptr;
|
||||
|
||||
if (armor_tint.Slot[material_slot].Color) {
|
||||
return armor_tint.Slot[material_slot].Color;
|
||||
}
|
||||
|
||||
item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
if (item != nullptr) {
|
||||
return item->Color;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @return
|
||||
*/
|
||||
int32 Mob::GetHerosForgeModel(uint8 material_slot) const
|
||||
{
|
||||
uint32 hero_model = 0;
|
||||
if (material_slot >= 0 && material_slot < EQEmu::textures::weaponPrimary) {
|
||||
uint32 ornamentation_aug_type = RuleI(Character, OrnamentationAugmentType);
|
||||
|
||||
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(material_slot));
|
||||
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
|
||||
if (item != nullptr && invslot != INVALID_INDEX) {
|
||||
if (IsClient()) {
|
||||
const EQEmu::ItemInstance *inst = CastToClient()->m_inv[invslot];
|
||||
if (inst) {
|
||||
if (inst->GetOrnamentationAug(ornamentation_aug_type)) {
|
||||
item = inst->GetOrnamentationAug(ornamentation_aug_type)->GetItem();
|
||||
hero_model = item->HerosForgeModel;
|
||||
}
|
||||
else if (inst->GetOrnamentHeroModel()) {
|
||||
hero_model = inst->GetOrnamentHeroModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hero_model == 0) {
|
||||
hero_model = item->HerosForgeModel;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
hero_model = CastToNPC()->GetHeroForgeModel();
|
||||
|
||||
/**
|
||||
* Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots
|
||||
*/
|
||||
if (hero_model > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 &&
|
||||
material_slot != 5) {
|
||||
hero_model = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-Convert Hero Model to match the slot
|
||||
*
|
||||
* Otherwise, use the exact Model if model is > 999
|
||||
* Robes for example are 11607 to 12107 in RoF
|
||||
*/
|
||||
if (hero_model > 0 && hero_model < 1000) {
|
||||
hero_model *= 100;
|
||||
hero_model += material_slot;
|
||||
}
|
||||
|
||||
return hero_model;
|
||||
}
|
||||
|
||||
uint32 NPC::GetEquippedItemFromTextureSlot(uint8 material_slot) const
|
||||
{
|
||||
if (material_slot > 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 inventory_slot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (inventory_slot == INVALID_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return equipment[inventory_slot];
|
||||
}
|
||||
|
||||
/**
|
||||
* NPCs typically use this function for sending appearance
|
||||
* @param one_client
|
||||
*/
|
||||
void Mob::SendArmorAppearance(Client *one_client)
|
||||
{
|
||||
/**
|
||||
* one_client of 0 means sent to all clients
|
||||
*
|
||||
* Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the
|
||||
* armor being worn and its mats, the client doesn't update the display
|
||||
* on arrival of these packets reliably.
|
||||
*
|
||||
* Send Wear changes if mob is a PC race and item is an armor slot.
|
||||
* The other packets work for primary/secondary.
|
||||
*/
|
||||
|
||||
Log(Logs::Detail, Logs::MobAppearance, "Mob::SendArmorAppearance [%s]",
|
||||
this->GetCleanName()
|
||||
);
|
||||
|
||||
if (IsPlayerRace(race)) {
|
||||
if (!IsClient()) {
|
||||
for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) {
|
||||
const EQEmu::ItemData *item = database.GetItem(GetEquippedItemFromTextureSlot(i));
|
||||
if (item != nullptr) {
|
||||
SendWearChange(i, one_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i <= EQEmu::textures::materialCount; ++i) {
|
||||
if (GetTextureProfileMaterial(i)) {
|
||||
SendWearChange(i, one_client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @param one_client
|
||||
*/
|
||||
void Mob::SendWearChange(uint8 material_slot, Client *one_client)
|
||||
{
|
||||
auto packet = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wear_change = (WearChange_Struct *) packet->pBuffer;
|
||||
|
||||
Log(Logs::Detail, Logs::MobAppearance, "Mob::SendWearChange [%s]",
|
||||
this->GetCleanName()
|
||||
);
|
||||
|
||||
wear_change->spawn_id = GetID();
|
||||
wear_change->material = static_cast<uint32>(GetEquipmentMaterial(material_slot));
|
||||
wear_change->elite_material = IsEliteMaterialItem(material_slot);
|
||||
wear_change->hero_forge_model = static_cast<uint32>(GetHerosForgeModel(material_slot));
|
||||
|
||||
#ifdef BOTS
|
||||
if (IsBot()) {
|
||||
auto item_inst = CastToBot()->GetBotItem(EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot));
|
||||
if (item_inst)
|
||||
wear_change->color.Color = item_inst->GetColor();
|
||||
else
|
||||
wear_change->color.Color = 0;
|
||||
}
|
||||
else {
|
||||
wear_change->color.Color = GetEquipmentColor(material_slot);
|
||||
}
|
||||
#else
|
||||
wear_change->color.Color = GetEquipmentColor(material_slot);
|
||||
#endif
|
||||
|
||||
wear_change->wear_slot_id = material_slot;
|
||||
|
||||
if (!one_client) {
|
||||
entity_list.QueueClients(this, packet);
|
||||
}
|
||||
else {
|
||||
one_client->QueuePacket(packet, false, Client::CLIENT_CONNECTED);
|
||||
}
|
||||
|
||||
safe_delete(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @param texture
|
||||
* @param hero_forge_model
|
||||
* @param elite_material
|
||||
* @param unknown06
|
||||
* @param unknown18
|
||||
*/
|
||||
void Mob::SendTextureWC(
|
||||
uint8 slot,
|
||||
uint16 texture,
|
||||
uint32 hero_forge_model,
|
||||
uint32 elite_material,
|
||||
uint32 unknown06,
|
||||
uint32 unknown18
|
||||
)
|
||||
{
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wear_change = (WearChange_Struct *) outapp->pBuffer;
|
||||
|
||||
if (this->IsClient()) {
|
||||
wear_change->color.Color = GetEquipmentColor(slot);
|
||||
}
|
||||
else {
|
||||
wear_change->color.Color = this->GetArmorTint(slot);
|
||||
}
|
||||
|
||||
wear_change->spawn_id = this->GetID();
|
||||
wear_change->material = texture;
|
||||
wear_change->wear_slot_id = slot;
|
||||
wear_change->unknown06 = unknown06;
|
||||
wear_change->elite_material = elite_material;
|
||||
wear_change->hero_forge_model = hero_forge_model;
|
||||
wear_change->unknown18 = unknown18;
|
||||
|
||||
SetMobTextureProfile(slot, texture, wear_change->color.Color, hero_forge_model);
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @param red_tint
|
||||
* @param green_tint
|
||||
* @param blue_tint
|
||||
*/
|
||||
void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint)
|
||||
{
|
||||
uint32 color;
|
||||
color = (red_tint & 0xFF) << 16;
|
||||
color |= (green_tint & 0xFF) << 8;
|
||||
color |= (blue_tint & 0xFF);
|
||||
color |= (color) ? (0xFF << 24) : 0;
|
||||
armor_tint.Slot[material_slot].Color = color;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wc = (WearChange_Struct *) outapp->pBuffer;
|
||||
|
||||
wc->spawn_id = this->GetID();
|
||||
wc->material = GetEquipmentMaterial(material_slot);
|
||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||
wc->color.Color = color;
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
SetMobTextureProfile(material_slot, texture, color);
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param material_slot
|
||||
* @param texture
|
||||
* @param color
|
||||
* @param hero_forge_model
|
||||
*/
|
||||
void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model)
|
||||
{
|
||||
armor_tint.Slot[material_slot].Color = color;
|
||||
|
||||
/**
|
||||
* Change internal values
|
||||
*/
|
||||
SetMobTextureProfile(material_slot, texture, color, hero_forge_model);
|
||||
|
||||
/**
|
||||
* Packet update
|
||||
*/
|
||||
auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct));
|
||||
auto *wear_change = (WearChange_Struct *) outapp->pBuffer;
|
||||
|
||||
wear_change->spawn_id = this->GetID();
|
||||
wear_change->material = texture;
|
||||
wear_change->hero_forge_model = hero_forge_model;
|
||||
wear_change->color.Color = color;
|
||||
wear_change->wear_slot_id = material_slot;
|
||||
|
||||
entity_list.QueueClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
143
zone/npc.cpp
143
zone/npc.cpp
@ -973,7 +973,7 @@ bool NPC::SpawnZoneController()
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
|
||||
strncpy(npc_type->name, "zone_controller", 60);
|
||||
npc_type->cur_hp = 2000000000;
|
||||
npc_type->current_hp = 2000000000;
|
||||
npc_type->max_hp = 2000000000;
|
||||
npc_type->hp_regen = 100000000;
|
||||
npc_type->race = 240;
|
||||
@ -1024,7 +1024,7 @@ NPC * NPC::SpawnGridNodeNPC(std::string name, const glm::vec4 &position, uint32
|
||||
sprintf(npc_type->name, "%u_%u", grid_id, grid_number);
|
||||
sprintf(npc_type->lastname, "Number: %u Grid: %u Pause: %u", grid_number, grid_id, pause);
|
||||
|
||||
npc_type->cur_hp = 4000000;
|
||||
npc_type->current_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 2254;
|
||||
npc_type->gender = 2;
|
||||
@ -1058,7 +1058,7 @@ NPC * NPC::SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4
|
||||
sprintf(npc_type->name, "%s", name.c_str());
|
||||
sprintf(npc_type->lastname, "%s", last_name.c_str());
|
||||
|
||||
npc_type->cur_hp = 4000000;
|
||||
npc_type->current_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 2254;
|
||||
npc_type->gender = 2;
|
||||
@ -1095,33 +1095,45 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
|
||||
else {
|
||||
Seperator sep(spawncommand);
|
||||
//Lets see if someone didn't fill out the whole #spawn function properly
|
||||
if (!sep.IsNumber(1))
|
||||
sprintf(sep.arg[1],"1");
|
||||
if (!sep.IsNumber(2))
|
||||
sprintf(sep.arg[2],"1");
|
||||
if (!sep.IsNumber(3))
|
||||
sprintf(sep.arg[3],"0");
|
||||
if (atoi(sep.arg[4]) > 2100000000 || atoi(sep.arg[4]) <= 0)
|
||||
sprintf(sep.arg[4]," ");
|
||||
if (!strcmp(sep.arg[5],"-"))
|
||||
sprintf(sep.arg[5]," ");
|
||||
if (!sep.IsNumber(5))
|
||||
sprintf(sep.arg[5]," ");
|
||||
if (!sep.IsNumber(6))
|
||||
sprintf(sep.arg[6],"1");
|
||||
if (!sep.IsNumber(8))
|
||||
sprintf(sep.arg[8],"0");
|
||||
if (!sep.IsNumber(9))
|
||||
if (!sep.IsNumber(1)) {
|
||||
sprintf(sep.arg[1], "1");
|
||||
}
|
||||
if (!sep.IsNumber(2)) {
|
||||
sprintf(sep.arg[2], "1");
|
||||
}
|
||||
if (!sep.IsNumber(3)) {
|
||||
sprintf(sep.arg[3], "0");
|
||||
}
|
||||
if (atoi(sep.arg[4]) > 2100000000 || atoi(sep.arg[4]) <= 0) {
|
||||
sprintf(sep.arg[4], " ");
|
||||
}
|
||||
if (!strcmp(sep.arg[5], "-")) {
|
||||
sprintf(sep.arg[5], " ");
|
||||
}
|
||||
if (!sep.IsNumber(5)) {
|
||||
sprintf(sep.arg[5], " ");
|
||||
}
|
||||
if (!sep.IsNumber(6)) {
|
||||
sprintf(sep.arg[6], "1");
|
||||
}
|
||||
if (!sep.IsNumber(8)) {
|
||||
sprintf(sep.arg[8], "0");
|
||||
}
|
||||
if (!sep.IsNumber(9)) {
|
||||
sprintf(sep.arg[9], "0");
|
||||
if (!sep.IsNumber(7))
|
||||
sprintf(sep.arg[7],"0");
|
||||
if (!strcmp(sep.arg[4],"-"))
|
||||
sprintf(sep.arg[4]," ");
|
||||
if (!sep.IsNumber(10)) // bodytype
|
||||
}
|
||||
if (!sep.IsNumber(7)) {
|
||||
sprintf(sep.arg[7], "0");
|
||||
}
|
||||
if (!strcmp(sep.arg[4], "-")) {
|
||||
sprintf(sep.arg[4], " ");
|
||||
}
|
||||
if (!sep.IsNumber(10)) { // bodytype
|
||||
sprintf(sep.arg[10], "0");
|
||||
}
|
||||
//Calc MaxHP if client neglected to enter it...
|
||||
if (!sep.IsNumber(4)) {
|
||||
sep.arg[4] = 0;
|
||||
if (sep.arg[4] && !sep.IsNumber(4)) {
|
||||
sprintf(sep.arg[4], "0");
|
||||
}
|
||||
|
||||
// Autoselect NPC Gender
|
||||
@ -1134,7 +1146,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
|
||||
strncpy(npc_type->name, sep.arg[0], 60);
|
||||
npc_type->cur_hp = atoi(sep.arg[4]);
|
||||
npc_type->current_hp = atoi(sep.arg[4]);
|
||||
npc_type->max_hp = atoi(sep.arg[4]);
|
||||
npc_type->race = atoi(sep.arg[1]);
|
||||
npc_type->gender = atoi(sep.arg[5]);
|
||||
@ -1487,38 +1499,49 @@ uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_ver
|
||||
|
||||
int32 NPC::GetEquipmentMaterial(uint8 material_slot) const
|
||||
{
|
||||
if (material_slot >= EQEmu::textures::materialCount)
|
||||
int32 texture_profile_material = GetTextureProfileMaterial(material_slot);
|
||||
|
||||
Log(Logs::Detail, Logs::MobAppearance, "NPC::GetEquipmentMaterial [%s] material_slot: %u",
|
||||
this->clean_name,
|
||||
material_slot
|
||||
);
|
||||
|
||||
if (texture_profile_material > 0) {
|
||||
return texture_profile_material;
|
||||
}
|
||||
|
||||
if (material_slot >= EQEmu::textures::materialCount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 invslot = EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot);
|
||||
if (invslot == INVALID_INDEX)
|
||||
if (invslot == INVALID_INDEX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (equipment[invslot] == 0)
|
||||
{
|
||||
switch(material_slot)
|
||||
{
|
||||
case EQEmu::textures::armorHead:
|
||||
return helmtexture;
|
||||
case EQEmu::textures::armorChest:
|
||||
return texture;
|
||||
case EQEmu::textures::armorArms:
|
||||
return armtexture;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return bracertexture;
|
||||
case EQEmu::textures::armorHands:
|
||||
return handtexture;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return legtexture;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return feettexture;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return d_melee_texture1;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return d_melee_texture2;
|
||||
default:
|
||||
//they have nothing in the slot, and its not a special slot... they get nothing.
|
||||
return(0);
|
||||
if (equipment[invslot] == 0) {
|
||||
switch (material_slot) {
|
||||
case EQEmu::textures::armorHead:
|
||||
return helmtexture;
|
||||
case EQEmu::textures::armorChest:
|
||||
return texture;
|
||||
case EQEmu::textures::armorArms:
|
||||
return armtexture;
|
||||
case EQEmu::textures::armorWrist:
|
||||
return bracertexture;
|
||||
case EQEmu::textures::armorHands:
|
||||
return handtexture;
|
||||
case EQEmu::textures::armorLegs:
|
||||
return legtexture;
|
||||
case EQEmu::textures::armorFeet:
|
||||
return feettexture;
|
||||
case EQEmu::textures::weaponPrimary:
|
||||
return d_melee_texture1;
|
||||
case EQEmu::textures::weaponSecondary:
|
||||
return d_melee_texture2;
|
||||
default:
|
||||
//they have nothing in the slot, and its not a special slot... they get nothing.
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2164,8 +2187,8 @@ void NPC::ModifyNPCStat(const char *identifier, const char *new_value)
|
||||
base_hp = atoi(val.c_str());
|
||||
|
||||
CalcMaxHP();
|
||||
if (cur_hp > max_hp) {
|
||||
cur_hp = max_hp;
|
||||
if (current_hp > max_hp) {
|
||||
current_hp = max_hp;
|
||||
}
|
||||
|
||||
return;
|
||||
@ -2346,14 +2369,14 @@ void NPC::LevelScale() {
|
||||
base_hp += (random_level - level) * 100;
|
||||
}
|
||||
|
||||
cur_hp = max_hp;
|
||||
current_hp = max_hp;
|
||||
max_dmg += (random_level - level) * 2;
|
||||
} else {
|
||||
uint8 scale_adjust = 1;
|
||||
|
||||
base_hp += (int)(base_hp * scaling);
|
||||
max_hp += (int)(max_hp * scaling);
|
||||
cur_hp = max_hp;
|
||||
current_hp = max_hp;
|
||||
|
||||
if (max_dmg) {
|
||||
max_dmg += (int)(max_dmg * scaling / scale_adjust);
|
||||
@ -2394,7 +2417,7 @@ void NPC::LevelScale() {
|
||||
ATK += (int)(ATK * scaling);
|
||||
base_hp += (int)(base_hp * scaling);
|
||||
max_hp += (int)(max_hp * scaling);
|
||||
cur_hp = max_hp;
|
||||
current_hp = max_hp;
|
||||
STR += (int)(STR * scaling / scale_adjust);
|
||||
STA += (int)(STA * scaling / scale_adjust);
|
||||
AGI += (int)(AGI * scaling / scale_adjust);
|
||||
|
||||
@ -311,7 +311,7 @@ public:
|
||||
void MoveTo(const glm::vec4& position, bool saveguardspot);
|
||||
void GetClosestWaypoint(std::list<wplist> &wp_list, int count, const glm::vec3& location);
|
||||
|
||||
uint32 GetEquipment(uint8 material_slot) const; // returns item id
|
||||
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id
|
||||
int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
|
||||
void NextGuardPosition();
|
||||
@ -468,6 +468,7 @@ public:
|
||||
|
||||
virtual int GetStuckBehavior() const { return NPCTypedata_ours ? NPCTypedata_ours->stuck_behavior : NPCTypedata->stuck_behavior; }
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
const NPCType* NPCTypedata;
|
||||
|
||||
@ -529,7 +529,7 @@ void PathfinderWaypoint::ShowNode(const Node &n) {
|
||||
|
||||
sprintf(npc_type->name, "%s", DigitToWord(n.id).c_str());
|
||||
sprintf(npc_type->lastname, "%i", n.id);
|
||||
npc_type->cur_hp = 4000000;
|
||||
npc_type->current_hp = 4000000;
|
||||
npc_type->max_hp = 4000000;
|
||||
npc_type->race = 2254;
|
||||
npc_type->gender = 2;
|
||||
|
||||
@ -639,7 +639,7 @@ XS(XS_Mob_GetEquipment) {
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetEquipment(material_slot);
|
||||
RETVAL = THIS->GetEquippedItemFromTextureSlot(material_slot);
|
||||
XSprePUSH;
|
||||
PUSHi((IV) RETVAL);
|
||||
}
|
||||
|
||||
@ -240,7 +240,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
if(scale_power > 0)
|
||||
{
|
||||
npc_type->max_hp *= (1 + scale_power);
|
||||
npc_type->cur_hp = npc_type->max_hp;
|
||||
npc_type->current_hp = npc_type->max_hp;
|
||||
npc_type->AC *= (1 + scale_power);
|
||||
npc_type->level += 1 + ((int)act_power / 25) > npc_type->level + RuleR(Pets, PetPowerLevelCap) ? RuleR(Pets, PetPowerLevelCap) : 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power
|
||||
npc_type->min_dmg = (npc_type->min_dmg * (1 + (scale_power / 2)));
|
||||
@ -255,7 +255,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
|
||||
|
||||
if (MaxHP){
|
||||
npc_type->max_hp += (npc_type->max_hp*MaxHP)/100;
|
||||
npc_type->cur_hp = npc_type->max_hp;
|
||||
npc_type->current_hp = npc_type->max_hp;
|
||||
}
|
||||
|
||||
//TODO: think about regen (engaged vs. not engaged)
|
||||
|
||||
@ -456,7 +456,7 @@ void Trap::CreateHiddenTrigger()
|
||||
auto make_npc = new NPCType;
|
||||
memcpy(make_npc, base_type, sizeof(NPCType));
|
||||
make_npc->max_hp = 100000;
|
||||
make_npc->cur_hp = 100000;
|
||||
make_npc->current_hp = 100000;
|
||||
strcpy(make_npc->name, "a_trap");
|
||||
make_npc->runspeed = 0.0f;
|
||||
make_npc->bodytype = BT_Special;
|
||||
|
||||
@ -2495,7 +2495,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
|
||||
temp_npctype_data->race = atoi(row[3]);
|
||||
temp_npctype_data->class_ = atoi(row[4]);
|
||||
temp_npctype_data->max_hp = atoi(row[5]);
|
||||
temp_npctype_data->cur_hp = temp_npctype_data->max_hp;
|
||||
temp_npctype_data->current_hp = temp_npctype_data->max_hp;
|
||||
temp_npctype_data->Mana = atoi(row[6]);
|
||||
temp_npctype_data->gender = atoi(row[7]);
|
||||
temp_npctype_data->texture = atoi(row[8]);
|
||||
@ -2777,7 +2777,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
|
||||
tmpNPCType->race = atoi(row[3]);
|
||||
tmpNPCType->class_ = atoi(row[4]);
|
||||
tmpNPCType->max_hp = atoi(row[5]);
|
||||
tmpNPCType->cur_hp = tmpNPCType->max_hp;
|
||||
tmpNPCType->current_hp = tmpNPCType->max_hp;
|
||||
tmpNPCType->Mana = atoi(row[6]);
|
||||
tmpNPCType->gender = atoi(row[7]);
|
||||
tmpNPCType->texture = atoi(row[8]);
|
||||
|
||||
@ -36,7 +36,7 @@ struct NPCType
|
||||
{
|
||||
char name[64];
|
||||
char lastname[70];
|
||||
int32 cur_hp;
|
||||
int32 current_hp;
|
||||
int32 max_hp;
|
||||
float size;
|
||||
float runspeed;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user