Texture work

This commit is contained in:
Akkadius 2018-12-31 03:18:59 -06:00
parent a24dfd35e8
commit 11a43cd320
34 changed files with 1229 additions and 756 deletions

View File

@ -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*/
};

View File

@ -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"
};
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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]); }

View File

@ -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;

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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; }

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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
);
}
//

View File

@ -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
View 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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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;

View File

@ -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]);

View File

@ -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;