mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 10:31:29 +00:00
Merge branch 'master' into lsid
This commit is contained in:
commit
3fdfc82ca0
@ -340,6 +340,7 @@ N(OP_MOTD),
|
||||
N(OP_MoveCoin),
|
||||
N(OP_MoveDoor),
|
||||
N(OP_MoveItem),
|
||||
N(OP_MoveMultipleItems),
|
||||
N(OP_MoveLogDisregard),
|
||||
N(OP_MoveLogRequest),
|
||||
N(OP_MultiLineMsg),
|
||||
|
||||
@ -1827,6 +1827,20 @@ struct MoveItem_Struct
|
||||
/*0028*/
|
||||
};
|
||||
|
||||
struct MultiMoveItemSub_Struct
|
||||
{
|
||||
/*0000*/ InventorySlot_Struct from_slot;
|
||||
/*0012*/ InventorySlot_Struct to_slot;
|
||||
/*0024*/ uint32 number_in_stack;
|
||||
/*0028*/ uint8 unknown[8];
|
||||
};
|
||||
|
||||
struct MultiMoveItem_Struct
|
||||
{
|
||||
/*0000*/ uint32 count;
|
||||
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||
};
|
||||
|
||||
//
|
||||
// from_slot/to_slot
|
||||
// -1 - destroy
|
||||
|
||||
@ -52,6 +52,25 @@ struct EnterWorld_Struct {
|
||||
struct WorldObjectsSent_Struct {
|
||||
};
|
||||
|
||||
// yep, even SoF had a version of the new inventory system, used by OP_MoveMultipleItems
|
||||
struct InventorySlot_Struct
|
||||
{
|
||||
/*000*/ int32 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Trade = 3, World = 4, Limbo = 5
|
||||
/*004*/ int32 Slot;
|
||||
/*008*/ int32 SubIndex;
|
||||
/*012*/ int32 AugIndex;
|
||||
/*016*/ int32 Unknown01;
|
||||
};
|
||||
|
||||
// unsure if they have a version of this, completeness though
|
||||
struct TypelessInventorySlot_Struct
|
||||
{
|
||||
/*000*/ int32 Slot;
|
||||
/*004*/ int32 SubIndex;
|
||||
/*008*/ int32 AugIndex;
|
||||
/*012*/ int32 Unknown01;
|
||||
};
|
||||
|
||||
/* Name Approval Struct */
|
||||
/* Len: */
|
||||
/* Opcode: 0x8B20*/
|
||||
@ -1557,6 +1576,19 @@ struct MoveItem_Struct
|
||||
/*0012*/
|
||||
};
|
||||
|
||||
struct MultiMoveItemSub_Struct
|
||||
{
|
||||
/*0000*/ InventorySlot_Struct from_slot;
|
||||
/*0020*/ uint32 number_in_stack; // so the amount we are moving from the source
|
||||
/*0024*/ InventorySlot_Struct to_slot;
|
||||
};
|
||||
|
||||
struct MultiMoveItem_Struct
|
||||
{
|
||||
/*0000*/ uint32 count;
|
||||
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||
};
|
||||
|
||||
//
|
||||
// from_slot/to_slot
|
||||
// -1 - destroy
|
||||
|
||||
@ -48,6 +48,23 @@ struct EnterWorld_Struct {
|
||||
/*068*/ uint32 return_home; // 01 on "Return Home", 00 if not
|
||||
};
|
||||
|
||||
// yep, even tit had a version of the new inventory system, used by OP_MoveMultipleItems
|
||||
struct InventorySlot_Struct
|
||||
{
|
||||
/*000*/ int32 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Trade = 3, World = 4, Limbo = 5
|
||||
/*004*/ int32 Slot;
|
||||
/*008*/ int32 SubIndex; // no aug index in Tit
|
||||
/*012*/ int32 Unknown01;
|
||||
};
|
||||
|
||||
// unsure if they have a version of this, completeness though
|
||||
struct TypelessInventorySlot_Struct
|
||||
{
|
||||
/*000*/ int32 Slot;
|
||||
/*004*/ int32 SubIndex; // no aug index in Tit
|
||||
/*008*/ int32 Unknown01;
|
||||
};
|
||||
|
||||
/* Name Approval Struct */
|
||||
/* Len: */
|
||||
/* Opcode: 0x8B20*/
|
||||
@ -1329,6 +1346,19 @@ struct MoveItem_Struct
|
||||
/*0012*/
|
||||
};
|
||||
|
||||
struct MultiMoveItemSub_Struct
|
||||
{
|
||||
/*0000*/ InventorySlot_Struct from_slot;
|
||||
/*0016*/ uint32 number_in_stack; // so the amount we are moving from the source
|
||||
/*0020*/ InventorySlot_Struct to_slot;
|
||||
};
|
||||
|
||||
struct MultiMoveItem_Struct
|
||||
{
|
||||
/*0000*/ uint32 count;
|
||||
/*0004*/ MultiMoveItemSub_Struct moves[0];
|
||||
};
|
||||
|
||||
//
|
||||
// from_slot/to_slot
|
||||
// -1 - destroy
|
||||
|
||||
@ -44,6 +44,7 @@ RULE_INT(Character, DeathExpLossMaxLevel, 255) // Any level greater than this wi
|
||||
RULE_INT(Character, DeathItemLossLevel, 10)
|
||||
RULE_INT(Character, DeathExpLossMultiplier, 3) //Adjust how much exp is lost
|
||||
RULE_BOOL(Character, UseDeathExpLossMult, false) //Adjust to use the above multiplier or to use code default.
|
||||
RULE_BOOL(Character, UseOldRaceRezEffects, false) // older clients had ID 757 for races with high starting STR, but it doesn't seem used anymore
|
||||
RULE_INT(Character, CorpseDecayTimeMS, 10800000)
|
||||
RULE_INT(Character, CorpseResTimeMS, 10800000) // time before cant res corpse(3 hours)
|
||||
RULE_BOOL(Character, LeaveCorpses, true)
|
||||
|
||||
@ -248,6 +248,7 @@ OP_AutoAttack=0x0d14
|
||||
OP_AutoAttack2=0x3912
|
||||
OP_Consume=0x4692
|
||||
OP_MoveItem=0x62a2
|
||||
OP_MoveMultipleItems=0x55ef
|
||||
OP_DeleteItem=0x3eb5
|
||||
OP_DeleteCharge=0x2d5b
|
||||
OP_ItemPacket=0x5e0e
|
||||
|
||||
@ -247,6 +247,7 @@ OP_AutoAttack=0x109d
|
||||
OP_AutoAttack2=0x3526
|
||||
OP_Consume=0x4b70
|
||||
OP_MoveItem=0x32ee
|
||||
OP_MoveMultipleItems=0x5623
|
||||
OP_DeleteItem=0x18ad
|
||||
OP_DeleteCharge=0x01b8
|
||||
OP_ItemPacket=0x368e
|
||||
|
||||
@ -241,6 +241,7 @@ OP_AutoAttack=0x3d86 # C
|
||||
OP_AutoAttack2=0x4ca1 # C
|
||||
OP_Consume=0x7ce4 # C
|
||||
OP_MoveItem=0x7f56 # C
|
||||
OP_MoveMultipleItems=0x4572
|
||||
OP_DeleteItem=0x36f8 # C
|
||||
OP_DeleteCharge=0x1df9 # C
|
||||
OP_ItemPacket=0x34f8 # C
|
||||
|
||||
@ -237,6 +237,7 @@ OP_AutoAttack=0x3427 #Trevius 01/20/09
|
||||
OP_AutoAttack2=0x6017 #Trevius 01/20/09
|
||||
OP_Consume=0x729a #Trevius 02/08/09
|
||||
OP_MoveItem=0x14B3 #Trevius 02/08/09
|
||||
OP_MoveMultipleItems=0x2d3e
|
||||
OP_DeleteItem=0x7DD4 #Xinu 03/08/09 0x41EE 0x018E 0x070C
|
||||
OP_DeleteCharge=0x32e2 #Trevius 03/23/09
|
||||
OP_ItemPacket=0x78Cd #Trevius 02/08/09
|
||||
|
||||
@ -198,6 +198,7 @@ OP_Split=0x4848 # ShowEQ 10/27/05
|
||||
OP_Surname=0x4668 # ShowEQ 10/27/05
|
||||
OP_ClearSurname=0x6cdb
|
||||
OP_MoveItem=0x420f # ShowEQ 10/27/05
|
||||
OP_MoveMultipleItems=0x463b
|
||||
OP_FaceChange=0x0f8e # ShowEQ 10/27/05
|
||||
OP_ItemPacket=0x3397 # ShowEQ 10/27/05
|
||||
OP_ItemLinkResponse=0x667c # ShowEQ 10/27/05
|
||||
|
||||
@ -251,6 +251,7 @@ OP_AutoAttack=0x1df9 # C
|
||||
OP_AutoAttack2=0x517b # C
|
||||
OP_Consume=0x24c5 # V
|
||||
OP_MoveItem=0x2641 # C
|
||||
OP_MoveMultipleItems=0x40e8
|
||||
OP_DeleteItem=0x66e0 # C
|
||||
OP_DeleteCharge=0x4ca1 # C
|
||||
OP_ItemPacket=0x7b6e # C
|
||||
|
||||
@ -369,6 +369,7 @@
|
||||
9113|2017_07_19_show_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'show_name'|empty|
|
||||
9114|2017_07_22_aura.sql|SHOW TABLES LIKE 'auras'|empty|
|
||||
9115|2017_10_28_traps.sql|SHOW COLUMNS FROM `traps` LIKE 'triggered_number'|empty|
|
||||
9116|2017_12_16_GroundSpawn_Respawn_Timer.sql|SHOW COLUMNS FROM `ground_spawns` WHERE Field = 'respawn_timer' AND Type = 'int(11) unsigned'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
ALTER TABLE `ground_spawns` MODIFY `respawn_timer` int(11) unsigned NOT NULL default 300;
|
||||
UPDATE `ground_spawns` SET `respawn_timer` = `respawn_timer` / 1000;
|
||||
@ -852,16 +852,56 @@ int Mob::ACSum()
|
||||
return ac;
|
||||
}
|
||||
|
||||
int Mob::GetBestMeleeSkill()
|
||||
{
|
||||
int bestSkill=0;
|
||||
EQEmu::skills::SkillType meleeSkills[]=
|
||||
{ EQEmu::skills::Skill1HBlunt,
|
||||
EQEmu::skills::Skill1HSlashing,
|
||||
EQEmu::skills::Skill2HBlunt,
|
||||
EQEmu::skills::Skill2HSlashing,
|
||||
EQEmu::skills::SkillHandtoHand,
|
||||
EQEmu::skills::Skill1HPiercing,
|
||||
EQEmu::skills::Skill2HPiercing,
|
||||
EQEmu::skills::SkillCount
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i=0; meleeSkills[i] != EQEmu::skills::SkillCount; ++i) {
|
||||
int value;
|
||||
value = GetSkill(meleeSkills[i]);
|
||||
bestSkill = std::max(value, bestSkill);
|
||||
}
|
||||
|
||||
return bestSkill;
|
||||
}
|
||||
|
||||
int Mob::offense(EQEmu::skills::SkillType skill)
|
||||
{
|
||||
int offense = GetSkill(skill);
|
||||
int stat_bonus = 0;
|
||||
if (skill == EQEmu::skills::SkillArchery || skill == EQEmu::skills::SkillThrowing)
|
||||
stat_bonus = GetDEX();
|
||||
else
|
||||
stat_bonus = GetSTR();
|
||||
int stat_bonus = GetSTR();
|
||||
|
||||
switch (skill) {
|
||||
case EQEmu::skills::SkillArchery:
|
||||
case EQEmu::skills::SkillThrowing:
|
||||
stat_bonus = GetDEX();
|
||||
break;
|
||||
|
||||
// Mobs with no weapons default to H2H.
|
||||
// Since H2H is capped at 100 for many many classes,
|
||||
// lets not handicap mobs based on not spawning with a
|
||||
// weapon.
|
||||
//
|
||||
// Maybe we tweak this if Disarm is actually implemented.
|
||||
|
||||
case EQEmu::skills::SkillHandtoHand:
|
||||
offense = GetBestMeleeSkill();
|
||||
break;
|
||||
}
|
||||
|
||||
if (stat_bonus >= 75)
|
||||
offense += (2 * stat_bonus - 150) / 3;
|
||||
|
||||
offense += GetATK();
|
||||
return offense;
|
||||
}
|
||||
@ -2676,9 +2716,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
// owner must get on list, but he's not actually gained any hate yet
|
||||
if (!owner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||
{
|
||||
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
|
||||
if (owner->IsClient() && !CheckAggro(owner))
|
||||
owner->CastToClient()->AddAutoXTarget(this);
|
||||
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5250,19 +5290,30 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
||||
// extra off hand non-sense, can only double with skill of 150 or above
|
||||
// or you have any amount of GiveDoubleAttack
|
||||
if (candouble && hand == EQEmu::inventory::slotSecondary)
|
||||
candouble = GetSkill(EQEmu::skills::SkillDoubleAttack) > 149 || (aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0;
|
||||
candouble =
|
||||
GetSkill(EQEmu::skills::SkillDoubleAttack) > 149 ||
|
||||
(aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack) > 0;
|
||||
|
||||
if (candouble) {
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillDoubleAttack, target, -10);
|
||||
if (CheckDoubleAttack()) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
|
||||
// Modern AA description: Increases your chance of ... performing one additional hit with a 2-handed weapon when double attacking by 2%.
|
||||
if (hand == EQEmu::inventory::slotPrimary) {
|
||||
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance +
|
||||
itembonuses.ExtraAttackChance;
|
||||
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
}
|
||||
|
||||
// you can only triple from the main hand
|
||||
if (hand == EQEmu::inventory::slotPrimary && CanThisClassTripleAttack()) {
|
||||
CheckIncreaseSkill(EQEmu::skills::SkillTripleAttack, target, -10);
|
||||
if (CheckTripleAttack()) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance +
|
||||
itembonuses.FlurryChance;
|
||||
itembonuses.FlurryChance;
|
||||
if (flurrychance && zone->random.Roll(flurrychance)) {
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
if (zone->random.Roll(flurrychance))
|
||||
@ -5273,12 +5324,6 @@ void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hand == EQEmu::inventory::slotPrimary) {
|
||||
auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance;
|
||||
if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance))
|
||||
Attack(target, hand, false, false, IsFromSpell);
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::CheckDualWield()
|
||||
|
||||
@ -291,6 +291,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_MercenaryTimerRequest] = &Client::Handle_OP_MercenaryTimerRequest;
|
||||
ConnectedOpcodes[OP_MoveCoin] = &Client::Handle_OP_MoveCoin;
|
||||
ConnectedOpcodes[OP_MoveItem] = &Client::Handle_OP_MoveItem;
|
||||
ConnectedOpcodes[OP_MoveMultipleItems] = &Client::Handle_OP_MoveMultipleItems;
|
||||
ConnectedOpcodes[OP_OpenContainer] = &Client::Handle_OP_OpenContainer;
|
||||
ConnectedOpcodes[OP_OpenGuildTributeMaster] = &Client::Handle_OP_OpenGuildTributeMaster;
|
||||
ConnectedOpcodes[OP_OpenInventory] = &Client::Handle_OP_OpenInventory;
|
||||
@ -9856,6 +9857,11 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app)
|
||||
{
|
||||
Kick(); // TODO: lets not desync though
|
||||
}
|
||||
|
||||
void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)
|
||||
{
|
||||
// Does not exist in Ti client
|
||||
|
||||
@ -204,6 +204,7 @@
|
||||
void Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveMultipleItems(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
||||
|
||||
@ -269,8 +269,16 @@ bool Client::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
if (force_spawn_updates && mob != this && distance <= client_update_range)
|
||||
mob->SendPositionUpdateToClient(this);
|
||||
if (force_spawn_updates && mob != this) {
|
||||
|
||||
if (mob->is_distance_roamer) {
|
||||
mob->SendPositionUpdateToClient(this);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (distance <= client_update_range)
|
||||
mob->SendPositionUpdateToClient(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1055,7 +1063,8 @@ void Client::OPRezzAnswer(uint32 Action, uint32 SpellID, uint16 ZoneID, uint16 I
|
||||
SetMana(0);
|
||||
SetHP(GetMaxHP()/5);
|
||||
int rez_eff = 756;
|
||||
if (GetRace() == BARBARIAN || GetRace() == DWARF || GetRace() == TROLL || GetRace() == OGRE)
|
||||
if (RuleB(Character, UseOldRaceRezEffects) &&
|
||||
(GetRace() == BARBARIAN || GetRace() == DWARF || GetRace() == TROLL || GetRace() == OGRE))
|
||||
rez_eff = 757;
|
||||
SpellOnTarget(rez_eff, this); // Rezz effects
|
||||
}
|
||||
|
||||
@ -376,6 +376,7 @@ int command_init(void)
|
||||
command_add("task", "(subcommand) - Task system commands", 150, command_task) ||
|
||||
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("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) ||
|
||||
@ -4168,6 +4169,26 @@ void command_tempname(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
void command_petname(Client *c, const Seperator *sep)
|
||||
{
|
||||
Mob *target;
|
||||
target = c->GetTarget();
|
||||
|
||||
if(!target)
|
||||
c->Message(0, "Usage: #petname newname (requires a target)");
|
||||
else if(target->IsPet() && (target->GetOwnerID() == c->GetID()) && strlen(sep->arg[1]) > 0)
|
||||
{
|
||||
char *oldname = strdup(target->GetName());
|
||||
target->TempName(sep->arg[1]);
|
||||
c->Message(0, "Renamed %s to %s", oldname, sep->arg[1]);
|
||||
free(oldname);
|
||||
}
|
||||
else {
|
||||
target->TempName();
|
||||
c->Message(0, "Restored the original name");
|
||||
}
|
||||
}
|
||||
|
||||
void command_npcspecialattk(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (c->GetTarget()==0 || c->GetTarget()->IsClient() || strlen(sep->arg[1]) <= 0 || strlen(sep->arg[2]) <= 0)
|
||||
|
||||
@ -287,6 +287,7 @@ void command_synctod(Client *c, const Seperator *sep);
|
||||
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_testspawn(Client *c, const Seperator *sep);
|
||||
void command_testspawnkill(Client *c, const Seperator *sep);
|
||||
void command_texture(Client *c, const Seperator *sep);
|
||||
|
||||
@ -611,6 +611,10 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the client does this check before calling CastSpell, should prevent discs being eaten
|
||||
if (spell.buffdurationformula != 0 && spell.targettype == ST_Self && HasDiscBuff())
|
||||
return false;
|
||||
|
||||
//Check the disc timer
|
||||
pTimerType DiscTimer = pTimerDisciplineReuseStart + spell.EndurTimerIndex;
|
||||
if(!p_timers.Expired(&database, DiscTimer, false)) { // lets not set the reuse timer in case CastSpell fails (or we would have to turn off the timer, but CastSpell will set it as well)
|
||||
|
||||
@ -327,8 +327,7 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Shouldn't race not affect AA XP?
|
||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
||||
{
|
||||
if(GetBaseRace() == HALFLING){
|
||||
@ -340,6 +339,12 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
}
|
||||
}
|
||||
|
||||
// why wasn't this here? Where should it be?
|
||||
if(zone->IsHotzone())
|
||||
{
|
||||
aatotalmod += RuleR(Zone, HotZoneBonus);
|
||||
}
|
||||
|
||||
if(RuleB(Zone, LevelBasedEXPMods)){
|
||||
if(zone->level_exp_mod[GetLevel()].ExpMod){
|
||||
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||
|
||||
162
zone/mob.cpp
162
zone/mob.cpp
@ -75,7 +75,6 @@ Mob::Mob(const char* in_name,
|
||||
uint32 in_drakkin_tattoo,
|
||||
uint32 in_drakkin_details,
|
||||
EQEmu::TintProfile in_armor_tint,
|
||||
|
||||
uint8 in_aa_title,
|
||||
uint8 in_see_invis, // see through invis/ivu
|
||||
uint8 in_see_invis_undead,
|
||||
@ -91,24 +90,24 @@ Mob::Mob(const char* in_name,
|
||||
uint8 in_handtexture,
|
||||
uint8 in_legtexture,
|
||||
uint8 in_feettexture
|
||||
) :
|
||||
) :
|
||||
attack_timer(2000),
|
||||
attack_dw_timer(2000),
|
||||
ranged_timer(2000),
|
||||
tic_timer(6000),
|
||||
mana_timer(2000),
|
||||
spellend_timer(0),
|
||||
rewind_timer(30000), //Timer used for determining amount of time between actual player position updates for /rewind.
|
||||
rewind_timer(30000),
|
||||
bindwound_timer(10000),
|
||||
stunned_timer(0),
|
||||
spun_timer(0),
|
||||
bardsong_timer(6000),
|
||||
gravity_timer(1000),
|
||||
viral_timer(0),
|
||||
m_FearWalkTarget(-999999.0f,-999999.0f,-999999.0f),
|
||||
m_FearWalkTarget(-999999.0f, -999999.0f, -999999.0f),
|
||||
m_TargetLocation(glm::vec3()),
|
||||
m_TargetV(glm::vec3()),
|
||||
flee_timer(FLEE_CHECK_TIMER),
|
||||
flee_timer(FLEE_CHECK_TIMER),
|
||||
m_Position(position),
|
||||
tmHidden(-1),
|
||||
mitigation_ac(0),
|
||||
@ -119,47 +118,46 @@ Mob::Mob(const char* in_name,
|
||||
position_update_melee_push_timer(1000)
|
||||
{
|
||||
targeted = 0;
|
||||
tar_ndx=0;
|
||||
tar_vector=0;
|
||||
tar_ndx = 0;
|
||||
tar_vector = 0;
|
||||
currently_fleeing = false;
|
||||
|
||||
last_z = 0;
|
||||
|
||||
last_major_update_position = m_Position;
|
||||
is_distance_roamer = false;
|
||||
|
||||
AI_Init();
|
||||
SetMoving(false);
|
||||
moved=false;
|
||||
moved = false;
|
||||
m_RewindLocation = glm::vec3();
|
||||
|
||||
_egnode = nullptr;
|
||||
name[0]=0;
|
||||
orig_name[0]=0;
|
||||
clean_name[0]=0;
|
||||
lastname[0]=0;
|
||||
if(in_name) {
|
||||
strn0cpy(name,in_name,64);
|
||||
strn0cpy(orig_name,in_name,64);
|
||||
name[0] = 0;
|
||||
orig_name[0] = 0;
|
||||
clean_name[0] = 0;
|
||||
lastname[0] = 0;
|
||||
if (in_name) {
|
||||
strn0cpy(name, in_name, 64);
|
||||
strn0cpy(orig_name, in_name, 64);
|
||||
}
|
||||
if(in_lastname)
|
||||
strn0cpy(lastname,in_lastname,64);
|
||||
cur_hp = in_cur_hp;
|
||||
max_hp = in_max_hp;
|
||||
base_hp = in_max_hp;
|
||||
gender = in_gender;
|
||||
race = in_race;
|
||||
base_gender = in_gender;
|
||||
base_race = in_race;
|
||||
class_ = in_class;
|
||||
bodytype = in_bodytype;
|
||||
if (in_lastname)
|
||||
strn0cpy(lastname, in_lastname, 64);
|
||||
cur_hp = in_cur_hp;
|
||||
max_hp = in_max_hp;
|
||||
base_hp = in_max_hp;
|
||||
gender = in_gender;
|
||||
race = in_race;
|
||||
base_gender = in_gender;
|
||||
base_race = in_race;
|
||||
class_ = in_class;
|
||||
bodytype = in_bodytype;
|
||||
orig_bodytype = in_bodytype;
|
||||
deity = in_deity;
|
||||
level = in_level;
|
||||
deity = in_deity;
|
||||
level = in_level;
|
||||
orig_level = in_level;
|
||||
npctype_id = in_npctype_id;
|
||||
size = in_size;
|
||||
base_size = size;
|
||||
runspeed = in_runspeed;
|
||||
npctype_id = in_npctype_id;
|
||||
size = in_size;
|
||||
base_size = size;
|
||||
runspeed = in_runspeed;
|
||||
// neotokyo: sanity check
|
||||
if (runspeed < 0 || runspeed > 20)
|
||||
runspeed = 1.25f;
|
||||
@ -172,7 +170,8 @@ Mob::Mob(const char* in_name,
|
||||
fearspeed = 0.625f;
|
||||
base_fearspeed = 25;
|
||||
// npcs
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
base_walkspeed = base_runspeed * 100 / 265;
|
||||
walkspeed = ((float)base_walkspeed) * 0.025f;
|
||||
base_fearspeed = base_runspeed * 100 / 127;
|
||||
@ -184,7 +183,7 @@ Mob::Mob(const char* in_name,
|
||||
|
||||
current_speed = base_runspeed;
|
||||
|
||||
m_PlayerState = 0;
|
||||
m_PlayerState = 0;
|
||||
|
||||
|
||||
// sanity check
|
||||
@ -196,8 +195,8 @@ Mob::Mob(const char* in_name,
|
||||
m_Light.Type[EQEmu::lightsource::LightActive] = m_Light.Type[EQEmu::lightsource::LightInnate];
|
||||
m_Light.Level[EQEmu::lightsource::LightActive] = m_Light.Level[EQEmu::lightsource::LightInnate];
|
||||
|
||||
texture = in_texture;
|
||||
helmtexture = in_helmtexture;
|
||||
texture = in_texture;
|
||||
helmtexture = in_helmtexture;
|
||||
armtexture = in_armtexture;
|
||||
bracertexture = in_bracertexture;
|
||||
handtexture = in_handtexture;
|
||||
@ -205,21 +204,21 @@ Mob::Mob(const char* in_name,
|
||||
feettexture = in_feettexture;
|
||||
multitexture = (armtexture || bracertexture || handtexture || legtexture || feettexture);
|
||||
|
||||
haircolor = in_haircolor;
|
||||
beardcolor = in_beardcolor;
|
||||
eyecolor1 = in_eyecolor1;
|
||||
eyecolor2 = in_eyecolor2;
|
||||
hairstyle = in_hairstyle;
|
||||
luclinface = in_luclinface;
|
||||
beard = in_beard;
|
||||
drakkin_heritage = in_drakkin_heritage;
|
||||
drakkin_tattoo = in_drakkin_tattoo;
|
||||
drakkin_details = in_drakkin_details;
|
||||
haircolor = in_haircolor;
|
||||
beardcolor = in_beardcolor;
|
||||
eyecolor1 = in_eyecolor1;
|
||||
eyecolor2 = in_eyecolor2;
|
||||
hairstyle = in_hairstyle;
|
||||
luclinface = in_luclinface;
|
||||
beard = in_beard;
|
||||
drakkin_heritage = in_drakkin_heritage;
|
||||
drakkin_tattoo = in_drakkin_tattoo;
|
||||
drakkin_details = in_drakkin_details;
|
||||
attack_speed = 0;
|
||||
attack_delay = 0;
|
||||
slow_mitigation = 0;
|
||||
findable = false;
|
||||
trackable = true;
|
||||
findable = false;
|
||||
trackable = true;
|
||||
has_shieldequiped = false;
|
||||
has_twohandbluntequiped = false;
|
||||
has_twohanderequipped = false;
|
||||
@ -230,19 +229,19 @@ Mob::Mob(const char* in_name,
|
||||
SpellPowerDistanceMod = 0;
|
||||
last_los_check = false;
|
||||
|
||||
if(in_aa_title>0)
|
||||
aa_title = in_aa_title;
|
||||
if (in_aa_title > 0)
|
||||
aa_title = in_aa_title;
|
||||
else
|
||||
aa_title =0xFF;
|
||||
AC = in_ac;
|
||||
ATK = in_atk;
|
||||
STR = in_str;
|
||||
STA = in_sta;
|
||||
DEX = in_dex;
|
||||
AGI = in_agi;
|
||||
INT = in_int;
|
||||
WIS = in_wis;
|
||||
CHA = in_cha;
|
||||
aa_title = 0xFF;
|
||||
AC = in_ac;
|
||||
ATK = in_atk;
|
||||
STR = in_str;
|
||||
STA = in_sta;
|
||||
DEX = in_dex;
|
||||
AGI = in_agi;
|
||||
INT = in_int;
|
||||
WIS = in_wis;
|
||||
CHA = in_cha;
|
||||
MR = CR = FR = DR = PR = Corrup = 0;
|
||||
|
||||
ExtraHaste = 0;
|
||||
@ -263,8 +262,8 @@ Mob::Mob(const char* in_name,
|
||||
hidden = false;
|
||||
improved_hidden = false;
|
||||
invulnerable = false;
|
||||
IsFullHP = (cur_hp == max_hp);
|
||||
qglobal=0;
|
||||
IsFullHP = (cur_hp == max_hp);
|
||||
qglobal = 0;
|
||||
spawned = false;
|
||||
|
||||
InitializeBuffSlots();
|
||||
@ -305,7 +304,7 @@ Mob::Mob(const char* in_name,
|
||||
logging_enabled = false;
|
||||
isgrouped = false;
|
||||
israidgrouped = false;
|
||||
|
||||
|
||||
IsHorse = false;
|
||||
|
||||
entity_id_being_looted = 0;
|
||||
@ -376,13 +375,13 @@ Mob::Mob(const char* in_name,
|
||||
}
|
||||
|
||||
destructibleobject = false;
|
||||
wandertype=0;
|
||||
pausetype=0;
|
||||
wandertype = 0;
|
||||
pausetype = 0;
|
||||
cur_wp = 0;
|
||||
m_CurrentWayPoint = glm::vec4();
|
||||
cur_wp_pause = 0;
|
||||
patrol=0;
|
||||
follow=0;
|
||||
patrol = 0;
|
||||
follow = 0;
|
||||
follow_dist = 100; // Default Distance for Follow
|
||||
no_target_hotkey = false;
|
||||
flee_mode = false;
|
||||
@ -396,7 +395,7 @@ Mob::Mob(const char* in_name,
|
||||
rooted = false;
|
||||
charmed = false;
|
||||
has_virus = false;
|
||||
for (i=0; i<MAX_SPELL_TRIGGER*2; i++) {
|
||||
for (i = 0; i < MAX_SPELL_TRIGGER * 2; i++) {
|
||||
viral_spells[i] = 0;
|
||||
}
|
||||
pStandingPetOrder = SPO_Follow;
|
||||
@ -427,7 +426,7 @@ Mob::Mob(const char* in_name,
|
||||
nimbus_effect3 = 0;
|
||||
m_targetable = true;
|
||||
|
||||
m_TargetRing = glm::vec3();
|
||||
m_TargetRing = glm::vec3();
|
||||
|
||||
flymode = FlyMode3;
|
||||
// Pathing
|
||||
@ -444,7 +443,7 @@ Mob::Mob(const char* in_name,
|
||||
m_AllowBeneficial = false;
|
||||
m_DisableMelee = false;
|
||||
for (int i = 0; i < EQEmu::skills::HIGHEST_SKILL + 2; i++) { SkillDmgTaken_Mod[i] = 0; }
|
||||
for (int i = 0; i < HIGHEST_RESIST+2; i++) { Vulnerability_Mod[i] = 0; }
|
||||
for (int i = 0; i < HIGHEST_RESIST + 2; i++) { Vulnerability_Mod[i] = 0; }
|
||||
|
||||
emoteid = 0;
|
||||
endur_upkeep = false;
|
||||
@ -1447,6 +1446,7 @@ void Mob::SendPosition() {
|
||||
if (DistanceSquared(last_major_update_position, m_Position) >= (100 * 100)) {
|
||||
entity_list.QueueClients(this, app, true, true);
|
||||
last_major_update_position = m_Position;
|
||||
is_distance_roamer = true;
|
||||
}
|
||||
else {
|
||||
entity_list.QueueCloseClients(this, app, true, RuleI(Range, MobPositionUpdates), nullptr, false);
|
||||
@ -1480,6 +1480,11 @@ void Mob::SendPositionUpdate(uint8 iSendToSelf) {
|
||||
CastToClient()->FastQueuePacket(&app, false);
|
||||
}
|
||||
}
|
||||
else if (DistanceSquared(last_major_update_position, m_Position) >= (100 * 100)) {
|
||||
entity_list.QueueClients(this, app, true, true);
|
||||
last_major_update_position = m_Position;
|
||||
is_distance_roamer = true;
|
||||
}
|
||||
else {
|
||||
entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), RuleI(Range, MobPositionUpdates), nullptr, false);
|
||||
}
|
||||
@ -3444,6 +3449,19 @@ void Mob::SetTarget(Mob* mob) {
|
||||
this->GetTarget()->SendHPUpdate(false, true);
|
||||
}
|
||||
|
||||
// For when we want a Ground Z at a location we are not at yet
|
||||
// Like MoveTo.
|
||||
float Mob::FindDestGroundZ(glm::vec3 dest, float z_offset)
|
||||
{
|
||||
float best_z = BEST_Z_INVALID;
|
||||
if (zone->zonemap != nullptr)
|
||||
{
|
||||
dest.z += z_offset;
|
||||
best_z = zone->zonemap->FindBestZ(dest, nullptr);
|
||||
}
|
||||
return best_z;
|
||||
}
|
||||
|
||||
float Mob::FindGroundZ(float new_x, float new_y, float z_offset)
|
||||
{
|
||||
float ret = BEST_Z_INVALID;
|
||||
|
||||
14
zone/mob.h
14
zone/mob.h
@ -162,6 +162,8 @@ public:
|
||||
inline virtual bool IsMob() const { return true; }
|
||||
inline virtual bool InZone() const { return true; }
|
||||
|
||||
bool is_distance_roamer;
|
||||
|
||||
//Somewhat sorted: needs documenting!
|
||||
|
||||
//Attack
|
||||
@ -199,6 +201,7 @@ public:
|
||||
void ApplyMeleeDamageMods(uint16 skill, int &damage, Mob * defender = nullptr, ExtraAttackOptions *opts = nullptr);
|
||||
int ACSum();
|
||||
int offense(EQEmu::skills::SkillType skill);
|
||||
int GetBestMeleeSkill();
|
||||
void CalcAC() { mitigation_ac = ACSum(); }
|
||||
int GetACSoftcap();
|
||||
double GetSoftcapReturns();
|
||||
@ -278,6 +281,7 @@ public:
|
||||
float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false,
|
||||
int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false,
|
||||
int level_override = -1);
|
||||
int GetResist(uint8 resist_type);
|
||||
int ResistPhysical(int level_diff, uint8 caster_level);
|
||||
int ResistElementalWeaponDmg(const EQEmu::ItemInstance *item);
|
||||
int CheckBaneDamage(const EQEmu::ItemInstance *item);
|
||||
@ -349,6 +353,7 @@ public:
|
||||
virtual int GetMaxSongSlots() const { return 0; }
|
||||
virtual int GetMaxDiscSlots() const { return 0; }
|
||||
virtual int GetMaxTotalSlots() const { return 0; }
|
||||
bool HasDiscBuff();
|
||||
virtual uint32 GetFirstBuffSlot(bool disc, bool song);
|
||||
virtual uint32 GetLastBuffSlot(bool disc, bool song);
|
||||
virtual void InitializeBuffSlots() { buffs = nullptr; current_buff_count = 0; }
|
||||
@ -954,7 +959,8 @@ public:
|
||||
void SendTo(float new_x, float new_y, float new_z);
|
||||
void SendToFixZ(float new_x, float new_y, float new_z);
|
||||
float GetZOffset() const;
|
||||
void FixZ(int32 z_find_offset = 5);
|
||||
void FixZ(int32 z_find_offset = 5);
|
||||
float GetFixedZ(glm::vec3 position, int32 z_find_offset = 5);
|
||||
void NPCSpecialAttacks(const char* parse, int permtag, bool reset = true, bool remove = false);
|
||||
inline uint32 DontHealMeBefore() const { return pDontHealMeBefore; }
|
||||
inline uint32 DontBuffMeBefore() const { return pDontBuffMeBefore; }
|
||||
@ -1108,8 +1114,6 @@ public:
|
||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);
|
||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
||||
|
||||
float last_z;
|
||||
|
||||
// Bots HealRotation methods
|
||||
#ifdef BOTS
|
||||
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
||||
@ -1225,7 +1229,8 @@ protected:
|
||||
uint32 npctype_id;
|
||||
glm::vec4 m_Position;
|
||||
/* Used to determine when an NPC has traversed so many units - to send a zone wide pos update */
|
||||
glm::vec4 last_major_update_position;
|
||||
glm::vec4 last_major_update_position;
|
||||
|
||||
int animation; // this is really what MQ2 calls SpeedRun just packed like (int)(SpeedRun * 40.0f)
|
||||
float base_size;
|
||||
float size;
|
||||
@ -1267,6 +1272,7 @@ protected:
|
||||
virtual int16 GetFocusEffect(focusType type, uint16 spell_id) { return 0; }
|
||||
void CalculateNewFearpoint();
|
||||
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||
float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0);
|
||||
glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
|
||||
void PrintRoute();
|
||||
|
||||
|
||||
@ -503,7 +503,7 @@ void NPC::AI_Start(uint32 iMoveDelay) {
|
||||
AIautocastspell_timer->Disable();
|
||||
} else {
|
||||
AIautocastspell_timer = std::unique_ptr<Timer>(new Timer(750));
|
||||
AIautocastspell_timer->Start(RandomTimer(0, 15000), false);
|
||||
AIautocastspell_timer->Start(RandomTimer(0, 300), false);
|
||||
}
|
||||
|
||||
if (NPCTypedata) {
|
||||
@ -1582,18 +1582,22 @@ void NPC::AI_DoMovement() {
|
||||
}
|
||||
|
||||
this->FixZ();
|
||||
|
||||
SendPosition();
|
||||
|
||||
//kick off event_waypoint arrive
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
|
||||
// start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted.
|
||||
if (!AI_walking_timer->Enabled())
|
||||
// No need to move as we are there. Next loop will
|
||||
// take care of normal grids, even at pause 0.
|
||||
// We do need to call and setup a wp if we're cur_wp=-2
|
||||
// as that is where roamer is unset and we don't want
|
||||
// the next trip through to move again based on grid stuff.
|
||||
doMove = false;
|
||||
if (cur_wp == -2) {
|
||||
AI_SetupNextWaypoint();
|
||||
else
|
||||
doMove = false;
|
||||
}
|
||||
|
||||
// wipe feign memory since we reached our first waypoint
|
||||
if(cur_wp == 1)
|
||||
ClearFeignMemory();
|
||||
@ -2593,7 +2597,7 @@ void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint32 iType,
|
||||
|
||||
// If we're going from an empty list, we need to start the timer
|
||||
if (AIspells.size() == 1)
|
||||
AIautocastspell_timer->Start(RandomTimer(0, 15000), false);
|
||||
AIautocastspell_timer->Start(RandomTimer(0, 300), false);
|
||||
}
|
||||
|
||||
void NPC::RemoveSpellFromNPCList(int16 spell_id)
|
||||
|
||||
@ -70,7 +70,7 @@ Object::Object(uint32 id, uint32 type, uint32 icon, const Object_Struct& object,
|
||||
|
||||
//creating a re-ocurring ground spawn.
|
||||
Object::Object(const EQEmu::ItemInstance* inst, char* name,float max_x,float min_x,float max_y,float min_y,float z,float heading,uint32 respawntimer)
|
||||
: respawn_timer(respawntimer), decay_timer(300000)
|
||||
: respawn_timer(respawntimer * 1000), decay_timer(300000)
|
||||
{
|
||||
|
||||
user = nullptr;
|
||||
|
||||
128
zone/spells.cpp
128
zone/spells.cpp
@ -3190,6 +3190,12 @@ uint32 Client::GetLastBuffSlot(bool disc, bool song)
|
||||
return GetCurrentBuffSlots();
|
||||
}
|
||||
|
||||
bool Mob::HasDiscBuff()
|
||||
{
|
||||
int slot = GetFirstBuffSlot(true, false);
|
||||
return buffs[slot].spellid != SPELL_UNKNOWN;
|
||||
}
|
||||
|
||||
// returns the slot the buff was added to, -1 if it wasn't added due to
|
||||
// stacking problems, and -2 if this is not a buff
|
||||
// if caster is null, the buff will be added with the caster level being
|
||||
@ -4431,6 +4437,36 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
|
||||
return false;
|
||||
}
|
||||
|
||||
int Mob::GetResist(uint8 resist_type)
|
||||
{
|
||||
switch(resist_type)
|
||||
{
|
||||
case RESIST_FIRE:
|
||||
return GetFR();
|
||||
case RESIST_COLD:
|
||||
return GetCR();
|
||||
case RESIST_MAGIC:
|
||||
return GetMR();
|
||||
case RESIST_DISEASE:
|
||||
return GetDR();
|
||||
case RESIST_POISON:
|
||||
return GetPR();
|
||||
case RESIST_CORRUPTION:
|
||||
return GetCorrup();
|
||||
case RESIST_PRISMATIC:
|
||||
return (GetFR() + GetCR() + GetMR() + GetDR() + GetPR()) / 5;
|
||||
case RESIST_CHROMATIC:
|
||||
return std::min({GetFR(), GetCR(), GetMR(), GetDR(), GetPR()});
|
||||
case RESIST_PHYSICAL:
|
||||
if (IsNPC())
|
||||
return GetPhR();
|
||||
else
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Spell resists:
|
||||
// returns an effectiveness index from 0 to 100. for most spells, 100 means
|
||||
@ -4514,68 +4550,16 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
return 100;
|
||||
}
|
||||
|
||||
int target_resist;
|
||||
switch(resist_type)
|
||||
{
|
||||
case RESIST_FIRE:
|
||||
target_resist = GetFR();
|
||||
break;
|
||||
case RESIST_COLD:
|
||||
target_resist = GetCR();
|
||||
break;
|
||||
case RESIST_MAGIC:
|
||||
target_resist = GetMR();
|
||||
break;
|
||||
case RESIST_DISEASE:
|
||||
target_resist = GetDR();
|
||||
break;
|
||||
case RESIST_POISON:
|
||||
target_resist = GetPR();
|
||||
break;
|
||||
case RESIST_CORRUPTION:
|
||||
target_resist = GetCorrup();
|
||||
break;
|
||||
case RESIST_PRISMATIC:
|
||||
target_resist = (GetFR() + GetCR() + GetMR() + GetDR() + GetPR()) / 5;
|
||||
break;
|
||||
case RESIST_CHROMATIC:
|
||||
{
|
||||
target_resist = GetFR();
|
||||
int temp = GetCR();
|
||||
if(temp < target_resist)
|
||||
{
|
||||
target_resist = temp;
|
||||
}
|
||||
int target_resist = GetResist(resist_type);
|
||||
|
||||
temp = GetMR();
|
||||
if(temp < target_resist)
|
||||
{
|
||||
target_resist = temp;
|
||||
}
|
||||
|
||||
temp = GetDR();
|
||||
if(temp < target_resist)
|
||||
{
|
||||
target_resist = temp;
|
||||
}
|
||||
|
||||
temp = GetPR();
|
||||
if(temp < target_resist)
|
||||
{
|
||||
target_resist = temp;
|
||||
}
|
||||
// JULY 24, 2002 changes
|
||||
int level = GetLevel();
|
||||
if (IsPetOwnerClient() && caster->IsNPC() && !caster->IsPetOwnerClient()) {
|
||||
auto owner = GetOwner();
|
||||
if (owner != nullptr) {
|
||||
target_resist = std::max(target_resist, owner->GetResist(resist_type));
|
||||
level = owner->GetLevel();
|
||||
}
|
||||
break;
|
||||
case RESIST_PHYSICAL:
|
||||
{
|
||||
if (IsNPC())
|
||||
target_resist = GetPhR();
|
||||
else
|
||||
target_resist = 0;
|
||||
}
|
||||
default:
|
||||
|
||||
target_resist = 0;
|
||||
}
|
||||
|
||||
//Setup our base resist chance.
|
||||
@ -4584,7 +4568,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
//Adjust our resist chance based on level modifiers
|
||||
uint8 caster_level = level_override > 0 ? level_override : caster->GetLevel();
|
||||
int temp_level_diff = GetLevel() - caster_level;
|
||||
int temp_level_diff = level - caster_level;
|
||||
|
||||
//Physical Resists are calclated using their own formula derived from extensive parsing.
|
||||
if (resist_type == RESIST_PHYSICAL) {
|
||||
@ -4593,7 +4577,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
else {
|
||||
|
||||
if(IsNPC() && GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
if(IsNPC() && level >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
int a = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
||||
if(a > 0)
|
||||
@ -4606,7 +4590,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
}
|
||||
}
|
||||
|
||||
if(IsClient() && GetLevel() >= 21 && temp_level_diff > 15)
|
||||
if(IsClient() && level >= 21 && temp_level_diff > 15)
|
||||
{
|
||||
temp_level_diff = 15;
|
||||
}
|
||||
@ -4622,16 +4606,16 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
level_mod = -level_mod;
|
||||
}
|
||||
|
||||
if(IsNPC() && (caster_level - GetLevel()) < -20)
|
||||
if(IsNPC() && (caster_level - level) < -20)
|
||||
{
|
||||
level_mod = 1000;
|
||||
}
|
||||
|
||||
//Even more level stuff this time dealing with damage spells
|
||||
if(IsNPC() && IsDamageSpell(spell_id) && GetLevel() >= 17)
|
||||
if(IsNPC() && IsDamageSpell(spell_id) && level >= 17)
|
||||
{
|
||||
int level_diff;
|
||||
if(GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
if(level >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
level_diff = (RuleI(Casting,ResistFalloff)-1) - caster_level;
|
||||
if(level_diff < 0)
|
||||
@ -4641,7 +4625,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
}
|
||||
else
|
||||
{
|
||||
level_diff = GetLevel() - caster_level;
|
||||
level_diff = level - caster_level;
|
||||
}
|
||||
level_mod += (2 * level_diff);
|
||||
}
|
||||
@ -4752,17 +4736,17 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
if(IsNPC())
|
||||
{
|
||||
if(GetLevel() > caster_level && GetLevel() >= 17 && caster_level <= 50)
|
||||
if(level > caster_level && level >= 17 && caster_level <= 50)
|
||||
{
|
||||
partial_modifier += 5;
|
||||
}
|
||||
|
||||
if(GetLevel() >= 30 && caster_level < 50)
|
||||
if(level >= 30 && caster_level < 50)
|
||||
{
|
||||
partial_modifier += (caster_level - 25);
|
||||
}
|
||||
|
||||
if(GetLevel() < 15)
|
||||
if(level < 15)
|
||||
{
|
||||
partial_modifier -= 5;
|
||||
}
|
||||
@ -4770,9 +4754,9 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
|
||||
if(caster->IsNPC())
|
||||
{
|
||||
if((GetLevel() - caster_level) >= 20)
|
||||
if((level - caster_level) >= 20)
|
||||
{
|
||||
partial_modifier += (GetLevel() - caster_level) * 1.5;
|
||||
partial_modifier += (level - caster_level) * 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -176,9 +176,15 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot)
|
||||
cur_wp = -2; // flag as quest controlled w/no grid
|
||||
Log(Logs::Detail, Logs::AI, "MoveTo %s without a grid.", to_string(static_cast<glm::vec3>(position)).c_str());
|
||||
}
|
||||
|
||||
glm::vec3 dest(position);
|
||||
|
||||
m_CurrentWayPoint = position;
|
||||
m_CurrentWayPoint.z = GetFixedZ(dest);
|
||||
|
||||
if (saveguardspot)
|
||||
{
|
||||
m_GuardPoint = position;
|
||||
m_GuardPoint = m_CurrentWayPoint;
|
||||
|
||||
if (m_GuardPoint.w == 0)
|
||||
m_GuardPoint.w = 0.0001; //hack to make IsGuarding simpler
|
||||
@ -189,7 +195,6 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot)
|
||||
Log(Logs::Detail, Logs::AI, "Setting guard position to %s", to_string(static_cast<glm::vec3>(m_GuardPoint)).c_str());
|
||||
}
|
||||
|
||||
m_CurrentWayPoint = position;
|
||||
cur_wp_pause = 0;
|
||||
pLastFightingDelayMoving = 0;
|
||||
if (AI_walking_timer->Enabled())
|
||||
@ -838,49 +843,61 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::FixZ(int32 z_find_offset /*= 5*/)
|
||||
float Mob::GetFixedZ(glm::vec3 dest, int32 z_find_offset)
|
||||
{
|
||||
|
||||
BenchTimer timer;
|
||||
timer.reset();
|
||||
float new_z = dest.z;
|
||||
|
||||
if (zone->HasMap() && RuleB(Map, FixZWhenMoving) && (flymode != 1 && flymode != 2))
|
||||
if (zone->HasMap() && RuleB(Map, FixZWhenMoving) &&
|
||||
(flymode != 1 && flymode != 2))
|
||||
{
|
||||
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
|
||||
(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
|
||||
if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap()
|
||||
|| (zone->HasWaterMap() &&
|
||||
!zone->watermap->InWater(glm::vec3(m_Position))))
|
||||
{
|
||||
/* Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors */
|
||||
float new_z = this->FindGroundZ(m_Position.x, m_Position.y, z_find_offset);
|
||||
new_z += this->GetZOffset();
|
||||
new_z = this->FindDestGroundZ(dest, z_find_offset);
|
||||
if (new_z != BEST_Z_INVALID)
|
||||
{
|
||||
new_z += this->GetZOffset();
|
||||
|
||||
auto duration = timer.elapsed();
|
||||
|
||||
Log(
|
||||
Logs::Moderate,
|
||||
Logs::FixZ,
|
||||
"Mob::FixZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf",
|
||||
this->GetCleanName(),
|
||||
new_z,
|
||||
m_Position.x,
|
||||
m_Position.y,
|
||||
m_Position.z,
|
||||
duration
|
||||
);
|
||||
|
||||
if ((new_z > -2000) && new_z != BEST_Z_INVALID) {
|
||||
if (RuleB(Map, MobZVisualDebug))
|
||||
this->SendAppearanceEffect(78, 0, 0, 0, 0);
|
||||
|
||||
m_Position.z = new_z;
|
||||
// If bad new Z restore old one
|
||||
if (new_z < -2000) {
|
||||
new_z = m_Position.z;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (RuleB(Map, MobZVisualDebug))
|
||||
this->SendAppearanceEffect(103, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f", this->GetCleanName(), std::abs(m_Position.z - new_z));
|
||||
}
|
||||
auto duration = timer.elapsed();
|
||||
|
||||
last_z = m_Position.z;
|
||||
Log(Logs::Moderate, Logs::FixZ,
|
||||
"Mob::GetFixedZ() (%s) returned %4.3f at %4.3f, %4.3f, %4.3f - Took %lf",
|
||||
this->GetCleanName(), new_z, dest.x, dest.y, dest.z, duration);
|
||||
}
|
||||
|
||||
return new_z;
|
||||
}
|
||||
|
||||
void Mob::FixZ(int32 z_find_offset /*= 5*/)
|
||||
{
|
||||
glm::vec3 current_loc(m_Position);
|
||||
float new_z = GetFixedZ(current_loc, z_find_offset);
|
||||
|
||||
if (new_z != m_Position.z)
|
||||
{
|
||||
if ((new_z > -2000) && new_z != BEST_Z_INVALID) {
|
||||
if (RuleB(Map, MobZVisualDebug))
|
||||
this->SendAppearanceEffect(78, 0, 0, 0, 0);
|
||||
|
||||
m_Position.z = new_z;
|
||||
}
|
||||
else {
|
||||
if (RuleB(Map, MobZVisualDebug))
|
||||
this->SendAppearanceEffect(103, 0, 0, 0, 0);
|
||||
|
||||
Log(Logs::General, Logs::FixZ, "%s is failing to find Z %f",
|
||||
this->GetCleanName(), std::abs(m_Position.z - new_z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user