mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
+11
-1
@@ -431,11 +431,20 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
|
||||
if (sender->GetPrimaryFaction() == 0 )
|
||||
return; // well, if we dont have a faction set, we're gonna be indiff to everybody
|
||||
|
||||
if (sender->HasAssistAggro())
|
||||
return;
|
||||
|
||||
for (auto it = npc_list.begin(); it != npc_list.end(); ++it) {
|
||||
NPC *mob = it->second;
|
||||
if (!mob)
|
||||
continue;
|
||||
|
||||
if (mob->CheckAggro(attacker))
|
||||
continue;
|
||||
|
||||
if (sender->NPCAssistCap() >= RuleI(Combat, NPCAssistCap))
|
||||
break;
|
||||
|
||||
float r = mob->GetAssistRange();
|
||||
r = r * r;
|
||||
|
||||
@@ -476,7 +485,8 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
|
||||
attacker->GetName(), DistanceSquared(mob->GetPosition(),
|
||||
sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ()));
|
||||
#endif
|
||||
mob->AddToHateList(attacker, 1, 0, false);
|
||||
mob->AddToHateList(attacker, 25, 0, false);
|
||||
sender->AddAssistCap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+68
-31
@@ -2009,15 +2009,15 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack
|
||||
}
|
||||
}
|
||||
|
||||
bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack_skill) {
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob->GetName(), damage, spell, attack_skill);
|
||||
bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attack_skill) {
|
||||
Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killer_mob->GetName(), damage, spell, attack_skill);
|
||||
|
||||
Mob *oos = nullptr;
|
||||
if(killerMob) {
|
||||
oos = killerMob->GetOwnerOrSelf();
|
||||
if(killer_mob) {
|
||||
oos = killer_mob->GetOwnerOrSelf();
|
||||
|
||||
char buffer[48] = { 0 };
|
||||
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
|
||||
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
|
||||
if(parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0)
|
||||
{
|
||||
if(GetHP() < 0) {
|
||||
@@ -2026,15 +2026,15 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
return false;
|
||||
}
|
||||
|
||||
if(killerMob && killerMob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
|
||||
if(killer_mob && killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
|
||||
char val1[20]={0};
|
||||
entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE,
|
||||
killerMob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
|
||||
killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
|
||||
}
|
||||
} else {
|
||||
|
||||
char buffer[48] = { 0 };
|
||||
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
|
||||
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
|
||||
if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0)
|
||||
{
|
||||
if(GetHP() < 0) {
|
||||
@@ -2072,21 +2072,21 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
EQApplicationPacket* app= new EQApplicationPacket(OP_Death,sizeof(Death_Struct));
|
||||
Death_Struct* d = (Death_Struct*)app->pBuffer;
|
||||
d->spawn_id = GetID();
|
||||
d->killer_id = killerMob ? killerMob->GetID() : 0;
|
||||
d->killer_id = killer_mob ? killer_mob->GetID() : 0;
|
||||
d->bindzoneid = 0;
|
||||
d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell;
|
||||
d->attack_skill = SkillDamageTypes[attack_skill];
|
||||
d->damage = damage;
|
||||
app->priority = 6;
|
||||
entity_list.QueueClients(killerMob, app, false);
|
||||
entity_list.QueueClients(killer_mob, app, false);
|
||||
|
||||
if(respawn2) {
|
||||
respawn2->DeathReset(1);
|
||||
}
|
||||
|
||||
if (killerMob) {
|
||||
if (killer_mob) {
|
||||
if(GetClass() != LDON_TREASURE)
|
||||
hate_list.AddEntToHateList(killerMob, damage);
|
||||
hate_list.AddEntToHateList(killer_mob, damage);
|
||||
}
|
||||
|
||||
safe_delete(app);
|
||||
@@ -2148,8 +2148,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
{
|
||||
if(!IsLdonTreasure && MerchantType == 0) {
|
||||
kr->SplitExp((finalxp), this);
|
||||
if(killerMob && (kr->IsRaidMember(killerMob->GetName()) || kr->IsRaidMember(killerMob->GetUltimateOwner()->GetName())))
|
||||
killerMob->TrySpellOnKill(killed_level,spell);
|
||||
if(killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName())))
|
||||
killer_mob->TrySpellOnKill(killed_level,spell);
|
||||
}
|
||||
/* Send the EVENT_KILLED_MERIT event for all raid members */
|
||||
for (int i = 0; i < MAX_RAID_MEMBERS; i++) {
|
||||
@@ -2193,8 +2193,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
{
|
||||
if(!IsLdonTreasure && MerchantType == 0) {
|
||||
kg->SplitExp((finalxp), this);
|
||||
if(killerMob && (kg->IsGroupMember(killerMob->GetName()) || kg->IsGroupMember(killerMob->GetUltimateOwner()->GetName())))
|
||||
killerMob->TrySpellOnKill(killed_level,spell);
|
||||
if(killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName())))
|
||||
killer_mob->TrySpellOnKill(killed_level,spell);
|
||||
}
|
||||
/* Send the EVENT_KILLED_MERIT event and update kill tasks
|
||||
* for all group members */
|
||||
@@ -2244,8 +2244,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
if(!GetOwner() || (GetOwner() && !GetOwner()->IsClient()))
|
||||
{
|
||||
give_exp_client->AddEXP((finalxp), conlevel);
|
||||
if(killerMob && (killerMob->GetID() == give_exp_client->GetID() || killerMob->GetUltimateOwner()->GetID() == give_exp_client->GetID()))
|
||||
killerMob->TrySpellOnKill(killed_level,spell);
|
||||
if(killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID()))
|
||||
killer_mob->TrySpellOnKill(killed_level,spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2393,20 +2393,30 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
uint16 emoteid = oos->GetEmoteID();
|
||||
if(emoteid != 0)
|
||||
oos->CastToNPC()->DoNPCEmote(KILLEDNPC, emoteid);
|
||||
killerMob->TrySpellOnKill(killed_level, spell);
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
}
|
||||
|
||||
WipeHateList();
|
||||
p_depop = true;
|
||||
if(killerMob && killerMob->GetTarget() == this) //we can kill things without having them targeted
|
||||
killerMob->SetTarget(nullptr); //via AE effects and such..
|
||||
if(killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted
|
||||
killer_mob->SetTarget(nullptr); //via AE effects and such..
|
||||
|
||||
entity_list.UpdateFindableNPCState(this, true);
|
||||
|
||||
char buffer[48] = { 0 };
|
||||
snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
|
||||
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill));
|
||||
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer, 0);
|
||||
|
||||
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
|
||||
if (RuleB(Zone, UseZoneController)) {
|
||||
if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && this->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
|
||||
char data_pass[100] = { 0 };
|
||||
snprintf(data_pass, 99, "%d %d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill), this->GetNPCTypeID());
|
||||
parse->EventNPC(EVENT_DEATH_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2422,6 +2432,11 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
||||
hate = 1;
|
||||
}
|
||||
|
||||
if (iYellForHelp)
|
||||
SetPrimaryAggro(true);
|
||||
else
|
||||
SetAssistAggro(true);
|
||||
|
||||
bool wasengaged = IsEngaged();
|
||||
Mob* owner = other->GetOwner();
|
||||
Mob* mypet = this->GetPet();
|
||||
@@ -2688,16 +2703,38 @@ uint8 Mob::GetWeaponDamageBonus(const Item_Struct *weapon, bool offhand)
|
||||
}
|
||||
} else {
|
||||
// 2h damage bonus
|
||||
int damage_bonus = 1 + (level - 28) / 3;
|
||||
if (delay <= 27)
|
||||
return 1 + ((level - 28) / 3);
|
||||
else if (delay < 40)
|
||||
return 1 + ((level - 28) / 3) + ((level - 30) / 5);
|
||||
else if (delay < 43)
|
||||
return 2 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3);
|
||||
else if (delay < 45)
|
||||
return 3 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3);
|
||||
else if (delay >= 45)
|
||||
return 4 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3);
|
||||
return damage_bonus + 1;
|
||||
// Client isn't reflecting what the dev quoted, this matches better
|
||||
if (level > 29) {
|
||||
int level_bonus = (level - 30) / 5 + 1;
|
||||
if (level > 50) {
|
||||
level_bonus++;
|
||||
int level_bonus2 = level - 50;
|
||||
if (level > 67)
|
||||
level_bonus2 += 5;
|
||||
else if (level > 59)
|
||||
level_bonus2 += 4;
|
||||
else if (level > 58)
|
||||
level_bonus2 += 3;
|
||||
else if (level > 56)
|
||||
level_bonus2 += 2;
|
||||
else if (level > 54)
|
||||
level_bonus2++;
|
||||
level_bonus += level_bonus2 * delay / 40;
|
||||
}
|
||||
damage_bonus += level_bonus;
|
||||
}
|
||||
if (delay >= 40) {
|
||||
int delay_bonus = (delay - 40) / 3 + 1;
|
||||
if (delay >= 45)
|
||||
delay_bonus += 2;
|
||||
else if (delay >= 43)
|
||||
delay_bonus++;
|
||||
damage_bonus += delay_bonus;
|
||||
}
|
||||
return damage_bonus;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -490,6 +490,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
(item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue))
|
||||
{
|
||||
newbon->skillmod[item->SkillModType] = item->SkillModValue;
|
||||
newbon->skillmodmax[item->SkillModType] = item->SkillModMax;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -679,7 +679,7 @@ public:
|
||||
|
||||
void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } }
|
||||
void IncreaseLanguageSkill(int skill_id, int value = 1);
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0) ? m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100 : m_pp.skills[skill_id]); } return 0; }
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_id) const {if (skill_id <= HIGHEST_SKILL) {return(itembonuses.skillmod[skill_id] > 0 ? (itembonuses.skillmodmax[skill_id] > 0 ? std::min(m_pp.skills[skill_id] + itembonuses.skillmodmax[skill_id], m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id]);} return 0;}
|
||||
uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; }
|
||||
bool HasSkill(SkillUseTypes skill_id) const;
|
||||
bool CanHaveSkill(SkillUseTypes skill_id) const;
|
||||
|
||||
+257
-115
@@ -2925,150 +2925,292 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
// Delegate to tradeskill object to perform combine
|
||||
AugmentItem_Struct* in_augment = (AugmentItem_Struct*)app->pBuffer;
|
||||
bool deleteItems = false;
|
||||
if (GetClientVersion() >= ClientVersion::RoF)
|
||||
{
|
||||
ItemInst *itemOneToPush = nullptr, *itemTwoToPush = nullptr;
|
||||
|
||||
//Message(15, "%i %i %i %i %i %i", in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id);
|
||||
//Log.Out(Logs::DebugLevel::Moderate, Logs::Debug, "cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i",
|
||||
// in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id);
|
||||
|
||||
// Adding augment
|
||||
if (in_augment->augment_action == 0)
|
||||
ItemInst *tobe_auged = nullptr, *old_aug = nullptr, *new_aug = nullptr, *aug = nullptr, *solvent = nullptr;
|
||||
Inventory& user_inv = GetInv();
|
||||
|
||||
uint16 item_slot = in_augment->container_slot;
|
||||
uint16 solvent_slot = in_augment->augment_slot;
|
||||
uint8 mat = Inventory::CalcMaterialFromSlot(item_slot); // for when player is augging a piece of equipment while they're wearing it
|
||||
|
||||
if (item_slot == INVALID_INDEX || solvent_slot == INVALID_INDEX)
|
||||
{
|
||||
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
|
||||
int8 slot = -1;
|
||||
Inventory& user_inv = GetInv();
|
||||
Message(13, "Error: Invalid Aug Index.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16 slot_id = in_augment->container_slot;
|
||||
uint16 aug_slot_id = in_augment->augment_slot;
|
||||
if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX)
|
||||
tobe_auged = user_inv.GetItem(item_slot);
|
||||
solvent = user_inv.GetItem(solvent_slot);
|
||||
|
||||
if (!tobe_auged)
|
||||
{
|
||||
Message(13, "Error: Invalid item passed for augmenting.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((in_augment->augment_action == 1) || (in_augment->augment_action == 2))
|
||||
{
|
||||
// Check for valid distiller if safely removing / swapping an augmentation
|
||||
|
||||
if (!solvent)
|
||||
{
|
||||
Message(13, "Error: Invalid Aug Index.");
|
||||
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment without a distiller.");
|
||||
Message(13, "Error: Missing an augmentation distiller for safely removing this augment.");
|
||||
return;
|
||||
}
|
||||
|
||||
tobe_auged = user_inv.GetItem(slot_id);
|
||||
auged_with = user_inv.GetItem(MainCursor);
|
||||
|
||||
if (tobe_auged && auged_with)
|
||||
else if (solvent->GetItem()->ItemType == ItemUseTypes::ItemTypeAugmentationDistiller)
|
||||
{
|
||||
if (((tobe_auged->IsAugmentSlotAvailable(auged_with->GetAugmentType(), in_augment->augment_index)) != -1) &&
|
||||
(tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots)))
|
||||
old_aug = tobe_auged->GetAugment(in_augment->augment_index);
|
||||
|
||||
if (!old_aug)
|
||||
{
|
||||
tobe_auged->PutAugment(in_augment->augment_index, *auged_with);
|
||||
tobe_auged->UpdateOrnamentationInfo();
|
||||
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove a nonexistent augment.");
|
||||
Message(13, "Error: No augment found in slot %i for safely removing.", in_augment->augment_index);
|
||||
return;
|
||||
}
|
||||
else if (solvent->GetItem()->ID != old_aug->GetItem()->AugDistiller)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", solvent->GetItem()->ID, old_aug->GetItem()->AugDistiller);
|
||||
Message(13, "Error: Wrong augmentation distiller for safely removing this augment.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (solvent->GetItem()->ItemType != ItemUseTypes::ItemTypePerfectedAugmentationDistiller)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with a non-distiller item.");
|
||||
Message(13, "Error: Invalid augmentation distiller for safely removing this augment.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index);
|
||||
if (aug) {
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(aug);
|
||||
parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||
|
||||
args.assign(1, tobe_auged);
|
||||
parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: Could not find augmentation at index %i. Aborting.", in_augment->augment_index);
|
||||
return;
|
||||
}
|
||||
|
||||
itemOneToPush = tobe_auged->Clone();
|
||||
// Must push items after the items in inventory are deleted - necessary due to lore items...
|
||||
if (itemOneToPush)
|
||||
{
|
||||
DeleteItemInInventory(slot_id, 0, true);
|
||||
DeleteItemInInventory(MainCursor, 0, true);
|
||||
|
||||
if (PutItemInInventory(slot_id, *itemOneToPush, true))
|
||||
{
|
||||
CalcBonuses();
|
||||
// Successfully added an augment to the item
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: No available slot for end result. Please free up the augment slot.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error in cloning item for augment. Aborted.");
|
||||
}
|
||||
switch (in_augment->augment_action)
|
||||
{
|
||||
case 0: // Adding an augment
|
||||
case 2: // Swapping augment
|
||||
new_aug = user_inv.GetItem(MainCursor);
|
||||
|
||||
if (!new_aug) // Shouldn't get the OP code without the augment on the user's cursor, but maybe it's h4x.
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "AugmentItem OpCode with 'Insert' or 'Swap' action received, but no augment on client's cursor.");
|
||||
Message(13, "Error: No augment found on cursor for inserting.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: No available slot for augment in that item.");
|
||||
if (((tobe_auged->IsAugmentSlotAvailable(new_aug->GetAugmentType(), in_augment->augment_index)) != -1) &&
|
||||
(tobe_auged->AvailableWearSlot(new_aug->GetItem()->Slots)))
|
||||
{
|
||||
old_aug = tobe_auged->RemoveAugment(in_augment->augment_index);
|
||||
if (old_aug)
|
||||
{
|
||||
// An old augment was removed in order to be replaced with the new one (augment_action 2)
|
||||
|
||||
CalcBonuses();
|
||||
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(old_aug);
|
||||
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||
|
||||
args.assign(1, tobe_auged);
|
||||
args.push_back(false);
|
||||
parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args);
|
||||
}
|
||||
|
||||
tobe_auged->PutAugment(in_augment->augment_index, *new_aug);
|
||||
tobe_auged->UpdateOrnamentationInfo();
|
||||
|
||||
aug = tobe_auged->GetAugment(in_augment->augment_index);
|
||||
if (aug)
|
||||
{
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(aug);
|
||||
parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||
|
||||
args.assign(1, tobe_auged);
|
||||
parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: Could not properly insert augmentation into augment slot %i. Aborting.", in_augment->augment_index);
|
||||
return;
|
||||
}
|
||||
|
||||
itemOneToPush = tobe_auged->Clone();
|
||||
if (old_aug)
|
||||
{
|
||||
itemTwoToPush = old_aug->Clone();
|
||||
}
|
||||
|
||||
// Must push items after the items in inventory are deleted - necessary due to lore items...
|
||||
if (itemOneToPush)
|
||||
{
|
||||
DeleteItemInInventory(item_slot, 0, true);
|
||||
DeleteItemInInventory(MainCursor, new_aug->IsStackable() ? 1 : 0, true);
|
||||
|
||||
if (solvent)
|
||||
{
|
||||
// Consume the augment distiller
|
||||
DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true);
|
||||
}
|
||||
|
||||
if (itemTwoToPush)
|
||||
{
|
||||
// This is a swap. Return the old aug to the player's cursor.
|
||||
if (!PutItemInInventory(MainCursor, *itemTwoToPush, true))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Problem returning old augment to player's cursor after augmentation swap.");
|
||||
Message(15, "Error: Failed to retrieve old augment after augmentation swap!");
|
||||
}
|
||||
}
|
||||
|
||||
if (PutItemInInventory(item_slot, *itemOneToPush, true))
|
||||
{
|
||||
// Successfully added an augment to the item
|
||||
|
||||
CalcBonuses();
|
||||
|
||||
if (mat != _MaterialInvalid)
|
||||
{
|
||||
SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: No available slot for end result. Please free up the augment slot.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error in cloning item for augment. Aborted.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: No available slot for augment in that item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (in_augment->augment_action == 1)
|
||||
{
|
||||
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
|
||||
int8 slot = -1;
|
||||
Inventory& user_inv = GetInv();
|
||||
|
||||
uint16 slot_id = in_augment->container_slot;
|
||||
uint16 aug_slot_id = in_augment->augment_slot; //it's actually solvent slot
|
||||
if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX)
|
||||
{
|
||||
Message(13, "Error: Invalid Aug Index.");
|
||||
return;
|
||||
}
|
||||
|
||||
tobe_auged = user_inv.GetItem(slot_id);
|
||||
auged_with = user_inv.GetItem(aug_slot_id);
|
||||
|
||||
ItemInst *old_aug = nullptr;
|
||||
if (!auged_with)
|
||||
return;
|
||||
const uint32 id = auged_with->GetID();
|
||||
ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index);
|
||||
if (aug) {
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(aug);
|
||||
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||
|
||||
args.assign(1, tobe_auged);
|
||||
|
||||
args.push_back(false);
|
||||
|
||||
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: Could not find augmentation at index %i. Aborting.");
|
||||
return;
|
||||
}
|
||||
old_aug = tobe_auged->RemoveAugment(in_augment->augment_index);
|
||||
tobe_auged->UpdateOrnamentationInfo();
|
||||
|
||||
itemOneToPush = tobe_auged->Clone();
|
||||
if (old_aug)
|
||||
itemTwoToPush = old_aug->Clone();
|
||||
if (itemOneToPush && itemTwoToPush && auged_with)
|
||||
{
|
||||
DeleteItemInInventory(slot_id, 0, true);
|
||||
DeleteItemInInventory(aug_slot_id, auged_with->IsStackable() ? 1 : 0, true);
|
||||
|
||||
if (!PutItemInInventory(slot_id, *itemOneToPush, true))
|
||||
break;
|
||||
case 1: // Removing augment safely (distiller)
|
||||
aug = tobe_auged->GetAugment(in_augment->augment_index);
|
||||
if (aug)
|
||||
{
|
||||
Message(15, "Failed to remove augment properly!");
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(aug);
|
||||
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||
|
||||
args.assign(1, tobe_auged);
|
||||
|
||||
args.push_back(false);
|
||||
|
||||
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||
}
|
||||
|
||||
if (PutItemInInventory(MainCursor, *itemTwoToPush, true))
|
||||
else
|
||||
{
|
||||
Message(13, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index);
|
||||
return;
|
||||
}
|
||||
|
||||
old_aug = tobe_auged->RemoveAugment(in_augment->augment_index);
|
||||
tobe_auged->UpdateOrnamentationInfo();
|
||||
|
||||
itemOneToPush = tobe_auged->Clone();
|
||||
if (old_aug)
|
||||
itemTwoToPush = old_aug->Clone();
|
||||
|
||||
if (itemOneToPush && itemTwoToPush)
|
||||
{
|
||||
// Consume the augment distiller
|
||||
DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true);
|
||||
|
||||
// Remove the augmented item
|
||||
DeleteItemInInventory(item_slot, 0, true);
|
||||
|
||||
// Replace it with the unaugmented item
|
||||
if (!PutItemInInventory(item_slot, *itemOneToPush, true))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after safe augment removal.");
|
||||
Message(15, "Error: Failed to return item after de-augmentation!");
|
||||
}
|
||||
|
||||
CalcBonuses();
|
||||
//Message(15, "Successfully removed an augmentation!");
|
||||
|
||||
if (mat != _MaterialInvalid)
|
||||
{
|
||||
SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed.
|
||||
}
|
||||
|
||||
// Drop the removed augment on the player's cursor
|
||||
if (!PutItemInInventory(MainCursor, *itemTwoToPush, true))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Problem returning augment to player's cursor after safe removal.");
|
||||
Message(15, "Error: Failed to return augment after removal from item!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: // Destroying augment (formerly done in birdbath/sealer with a solvent)
|
||||
|
||||
// RoF client does not require an augmentation solvent for destroying an augmentation in an item.
|
||||
// Augments can be destroyed with a right click -> Destroy at any time.
|
||||
|
||||
aug = tobe_auged->GetAugment(in_augment->augment_index);
|
||||
if (aug)
|
||||
{
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(aug);
|
||||
parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args);
|
||||
|
||||
args.assign(1, tobe_auged);
|
||||
|
||||
args.push_back(true);
|
||||
|
||||
parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Message(13, "Error: Could not find augmentation to remove at index %i. Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
tobe_auged->DeleteAugment(in_augment->augment_index);
|
||||
tobe_auged->UpdateOrnamentationInfo();
|
||||
|
||||
itemOneToPush = tobe_auged->Clone();
|
||||
if (itemOneToPush)
|
||||
{
|
||||
DeleteItemInInventory(item_slot, 0, true);
|
||||
|
||||
if (!PutItemInInventory(item_slot, *itemOneToPush, true))
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after augment deletion.");
|
||||
Message(15, "Error: Failed to return item after destroying augment!");
|
||||
}
|
||||
}
|
||||
|
||||
CalcBonuses();
|
||||
|
||||
if (mat != _MaterialInvalid)
|
||||
{
|
||||
SendWearChange(mat);
|
||||
}
|
||||
break;
|
||||
default: // Unknown
|
||||
Log.Out(Logs::General, Logs::Inventory, "Unrecognized augmentation action - cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i",
|
||||
in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Delegate to tradeskill object to perform combine
|
||||
Object::HandleAugmentation(this, in_augment, m_tradeskill_object);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -278,6 +278,7 @@ struct StatBonuses {
|
||||
float AggroRange; // when calculate just replace original value with this
|
||||
float AssistRange;
|
||||
int32 skillmod[HIGHEST_SKILL+1];
|
||||
int32 skillmodmax[HIGHEST_SKILL+1];
|
||||
int effective_casting_level;
|
||||
int reflect_chance; // chance to reflect incoming spell
|
||||
uint32 singingMod;
|
||||
|
||||
+18
-1
@@ -114,7 +114,9 @@ const char *QuestEventSubroutines[_LargestEventID] = {
|
||||
"EVENT_RESPAWN",
|
||||
"EVENT_DEATH_COMPLETE",
|
||||
"EVENT_UNHANDLED_OPCODE",
|
||||
"EVENT_TICK"
|
||||
"EVENT_TICK",
|
||||
"EVENT_SPAWN_ZONE",
|
||||
"EVENT_DEATH_ZONE",
|
||||
};
|
||||
|
||||
PerlembParser::PerlembParser() : perl(nullptr) {
|
||||
@@ -1424,6 +1426,21 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
|
||||
ExportVar(package_name.c_str(), "slotid", extradata);
|
||||
break;
|
||||
}
|
||||
case EVENT_SPAWN_ZONE: {
|
||||
Seperator sep(data);
|
||||
ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]);
|
||||
ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]);
|
||||
break;
|
||||
}
|
||||
case EVENT_DEATH_ZONE: {
|
||||
Seperator sep(data);
|
||||
ExportVar(package_name.c_str(), "killer_id", sep.arg[0]);
|
||||
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
|
||||
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
|
||||
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
|
||||
ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
|
||||
@@ -2919,6 +2919,29 @@ XS(XS__UpdateInstanceTimer) {
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__GetInstanceTimer);
|
||||
XS(XS__GetInstanceTimer) {
|
||||
dXSARGS;
|
||||
if (items != 0)
|
||||
Perl_croak(aTHX_ "Usage: GetInstanceTimer()");
|
||||
|
||||
uint32 timer = quest_manager.GetInstanceTimer();
|
||||
|
||||
XSRETURN_UV(timer);
|
||||
}
|
||||
|
||||
XS(XS__GetInstanceTimerByID);
|
||||
XS(XS__GetInstanceTimerByID) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: GetInstanceTimerByID(instance_id)");
|
||||
|
||||
uint16 instance_id = (uint16)SvUV(ST(0));
|
||||
uint32 timer = quest_manager.GetInstanceTimerByID(instance_id);
|
||||
|
||||
XSRETURN_UV(timer);
|
||||
}
|
||||
|
||||
XS(XS__GetInstanceID);
|
||||
XS(XS__GetInstanceID) {
|
||||
dXSARGS;
|
||||
@@ -3614,6 +3637,19 @@ XS(XS__debug)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__UpdateZoneHeader);
|
||||
XS(XS__UpdateZoneHeader) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: UpdateZoneHeader(type, value)");
|
||||
|
||||
std::string type = (std::string)SvPV_nolen(ST(0));
|
||||
std::string value = (std::string)SvPV_nolen(ST(1));
|
||||
quest_manager.UpdateZoneHeader(type, value);
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This is the callback perl will look for to setup the
|
||||
@@ -3650,6 +3686,8 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file);
|
||||
newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file);
|
||||
newXS(strcpy(buf, "UpdateInstanceTimer"), XS__UpdateInstanceTimer, file);
|
||||
newXS(strcpy(buf, "GetInstanceTimer"), XS__GetInstanceTimer, file);
|
||||
newXS(strcpy(buf, "GetInstanceTimerByID"), XS__GetInstanceTimerByID, file);
|
||||
newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file);
|
||||
newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file);
|
||||
newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file);
|
||||
@@ -3841,6 +3879,7 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file);
|
||||
newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file);
|
||||
newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file);
|
||||
newXS(strcpy(buf, "UpdateZoneHeader"), XS__UpdateZoneHeader, file);
|
||||
newXS(strcpy(buf, "varlink"), XS__varlink, file);
|
||||
newXS(strcpy(buf, "voicetell"), XS__voicetell, file);
|
||||
newXS(strcpy(buf, "we"), XS__we, file);
|
||||
|
||||
@@ -641,8 +641,18 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
|
||||
{
|
||||
npc->SetID(GetFreeID());
|
||||
npc->SetMerchantProbability((uint8) zone->random.Int(0, 99));
|
||||
|
||||
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
|
||||
|
||||
/* Zone controller process EVENT_SPAWN_ZONE */
|
||||
if (RuleB(Zone, UseZoneController)) {
|
||||
if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
|
||||
char data_pass[100] = { 0 };
|
||||
snprintf(data_pass, 99, "%d %d", npc->GetID(), npc->GetNPCTypeID());
|
||||
parse->EventNPC(EVENT_SPAWN_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 emoteid = npc->GetEmoteID();
|
||||
if (emoteid != 0)
|
||||
npc->DoNPCEmote(ONSPAWN, emoteid);
|
||||
|
||||
+2
-1
@@ -83,7 +83,8 @@ typedef enum {
|
||||
EVENT_DEATH_COMPLETE,
|
||||
EVENT_UNHANDLED_OPCODE,
|
||||
EVENT_TICK,
|
||||
|
||||
EVENT_SPAWN_ZONE,
|
||||
EVENT_DEATH_ZONE,
|
||||
_LargestEventID
|
||||
} QuestEventID;
|
||||
|
||||
|
||||
+15
-1
@@ -808,6 +808,14 @@ void lua_update_instance_timer(uint16 instance_id, uint32 new_duration) {
|
||||
quest_manager.UpdateInstanceTimer(instance_id, new_duration);
|
||||
}
|
||||
|
||||
uint32 lua_get_instance_timer() {
|
||||
return quest_manager.GetInstanceTimer();
|
||||
}
|
||||
|
||||
uint32 lua_get_instance_timer_by_id(uint16 instance_id) {
|
||||
return quest_manager.GetInstanceTimerByID(instance_id);
|
||||
}
|
||||
|
||||
int lua_get_instance_id(const char *zone, uint32 version) {
|
||||
return quest_manager.GetInstanceID(zone, version);
|
||||
}
|
||||
@@ -1296,6 +1304,10 @@ void lua_debug(std::string message, int level) {
|
||||
Log.Out(static_cast<Logs::DebugLevel>(level), Logs::QuestDebug, message);
|
||||
}
|
||||
|
||||
void lua_update_zone_header(std::string type, std::string value) {
|
||||
quest_manager.UpdateZoneHeader(type, value);
|
||||
}
|
||||
|
||||
#define LuaCreateNPCParse(name, c_type, default_value) do { \
|
||||
cur = table[#name]; \
|
||||
if(luabind::type(cur) != LUA_TNIL) { \
|
||||
@@ -1719,7 +1731,9 @@ luabind::scope lua_register_events() {
|
||||
luabind::value("leave_area", static_cast<int>(EVENT_LEAVE_AREA)),
|
||||
luabind::value("death_complete", static_cast<int>(EVENT_DEATH_COMPLETE)),
|
||||
luabind::value("unhandled_opcode", static_cast<int>(EVENT_UNHANDLED_OPCODE)),
|
||||
luabind::value("tick", static_cast<int>(EVENT_TICK))
|
||||
luabind::value("tick", static_cast<int>(EVENT_TICK)),
|
||||
luabind::value("spawn_zone", static_cast<int>(EVENT_SPAWN_ZONE)),
|
||||
luabind::value("death_zone", static_cast<int>(EVENT_DEATH_ZONE))
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+121
-1
@@ -1881,6 +1881,106 @@ bool Lua_Mob::IsBlind() {
|
||||
return self->IsBlind();
|
||||
}
|
||||
|
||||
uint8 Lua_Mob::SeeInvisible() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->SeeInvisible();
|
||||
}
|
||||
|
||||
bool Lua_Mob::SeeInvisibleUndead() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SeeInvisibleUndead();
|
||||
}
|
||||
|
||||
bool Lua_Mob::SeeHide() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SeeHide();
|
||||
}
|
||||
|
||||
bool Lua_Mob::SeeImprovedHide() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->SeeImprovedHide();
|
||||
}
|
||||
|
||||
uint8 Lua_Mob::GetNimbusEffect1() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetNimbusEffect1();
|
||||
}
|
||||
|
||||
uint8 Lua_Mob::GetNimbusEffect2() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetNimbusEffect2();
|
||||
}
|
||||
|
||||
uint8 Lua_Mob::GetNimbusEffect3() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetNimbusEffect3();
|
||||
}
|
||||
|
||||
bool Lua_Mob::IsTargetable() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsTargetable();
|
||||
}
|
||||
|
||||
bool Lua_Mob::HasShieldEquiped() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasShieldEquiped();
|
||||
}
|
||||
|
||||
bool Lua_Mob::HasTwoHandBluntEquiped() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasTwoHandBluntEquiped();
|
||||
}
|
||||
|
||||
bool Lua_Mob::HasTwoHanderEquipped() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasTwoHanderEquipped();
|
||||
}
|
||||
|
||||
uint32 Lua_Mob::GetHerosForgeModel(uint8 material_slot) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetHerosForgeModel(material_slot);
|
||||
}
|
||||
|
||||
uint32 Lua_Mob::IsEliteMaterialItem(uint8 material_slot) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->IsEliteMaterialItem(material_slot);
|
||||
}
|
||||
|
||||
float Lua_Mob::GetBaseSize() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->GetBaseSize();
|
||||
}
|
||||
|
||||
bool Lua_Mob::HasOwner() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasOwner();
|
||||
}
|
||||
|
||||
bool Lua_Mob::IsPet() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsPet();
|
||||
}
|
||||
|
||||
bool Lua_Mob::HasPet() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->HasPet();
|
||||
}
|
||||
|
||||
bool Lua_Mob::IsSilenced() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsSilenced();
|
||||
}
|
||||
|
||||
bool Lua_Mob::IsAmnesiad() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsAmnesiad();
|
||||
}
|
||||
|
||||
int32 Lua_Mob::GetMeleeMitigation() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetMeleeMitigation();
|
||||
}
|
||||
|
||||
luabind::scope lua_register_mob() {
|
||||
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
||||
.def(luabind::constructor<>())
|
||||
@@ -2203,7 +2303,27 @@ luabind::scope lua_register_mob() {
|
||||
.def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot)
|
||||
.def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack)
|
||||
.def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack)
|
||||
.def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot);
|
||||
.def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot)
|
||||
.def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible)
|
||||
.def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead)
|
||||
.def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide)
|
||||
.def("SeeImprovedHide", (bool(Lua_Mob::*)(bool))&Lua_Mob::SeeImprovedHide)
|
||||
.def("GetNimbusEffect1", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect1)
|
||||
.def("GetNimbusEffect2", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect2)
|
||||
.def("GetNimbusEffect3", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect3)
|
||||
.def("IsTargetable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTargetable)
|
||||
.def("HasShieldEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasShieldEquiped)
|
||||
.def("HasTwoHandBluntEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHandBluntEquiped)
|
||||
.def("HasTwoHanderEquipped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHanderEquipped)
|
||||
.def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel)
|
||||
.def("IsEliteMaterialItem", (uint32(Lua_Mob::*)(uint8))&Lua_Mob::IsEliteMaterialItem)
|
||||
.def("GetBaseSize", (double(Lua_Mob::*)(void))&Lua_Mob::GetBaseSize)
|
||||
.def("HasOwner", (bool(Lua_Mob::*)(void))&Lua_Mob::HasOwner)
|
||||
.def("IsPet", (bool(Lua_Mob::*)(void))&Lua_Mob::IsPet)
|
||||
.def("HasPet", (bool(Lua_Mob::*)(void))&Lua_Mob::HasPet)
|
||||
.def("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced)
|
||||
.def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad)
|
||||
.def("GetMeleeMitigation", (int32(Lua_Mob::*)(void))&Lua_Mob::GetMeleeMitigation);
|
||||
}
|
||||
|
||||
luabind::scope lua_register_special_abilities() {
|
||||
|
||||
@@ -358,6 +358,26 @@ public:
|
||||
int CanBuffStack(int spell_id, int caster_level);
|
||||
int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite);
|
||||
void SetPseudoRoot(bool in);
|
||||
uint8 SeeInvisible();
|
||||
bool SeeInvisibleUndead();
|
||||
bool SeeHide();
|
||||
bool SeeImprovedHide();
|
||||
uint8 GetNimbusEffect1();
|
||||
uint8 GetNimbusEffect2();
|
||||
uint8 GetNimbusEffect3();
|
||||
bool IsTargetable();
|
||||
bool HasShieldEquiped();
|
||||
bool HasTwoHandBluntEquiped();
|
||||
bool HasTwoHanderEquipped();
|
||||
uint32 GetHerosForgeModel(uint8 material_slot);
|
||||
uint32 IsEliteMaterialItem(uint8 material_slot);
|
||||
float GetBaseSize();
|
||||
bool HasOwner();
|
||||
bool IsPet();
|
||||
bool HasPet();
|
||||
bool IsSilenced();
|
||||
bool IsAmnesiad();
|
||||
int32 GetMeleeMitigation();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -117,7 +117,9 @@ const char *LuaEvents[_LargestEventID] = {
|
||||
"event_respawn",
|
||||
"event_death_complete",
|
||||
"event_unhandled_opcode",
|
||||
"event_tick"
|
||||
"event_tick",
|
||||
"event_spawn_zone",
|
||||
"event_death_zone"
|
||||
};
|
||||
|
||||
extern Zone *zone;
|
||||
|
||||
@@ -433,6 +433,9 @@ Mob::Mob(const char* in_name,
|
||||
|
||||
emoteid = 0;
|
||||
endur_upkeep = false;
|
||||
PrimaryAggro = false;
|
||||
AssistAggro = false;
|
||||
npc_assist_cap = 0;
|
||||
}
|
||||
|
||||
Mob::~Mob()
|
||||
@@ -2693,6 +2696,8 @@ bool Mob::RemoveFromHateList(Mob* mob)
|
||||
{
|
||||
AI_Event_NoLongerEngaged();
|
||||
zone->DelAggroMob();
|
||||
if (IsNPC() && !RuleB(Aggro, AllowTickPulling))
|
||||
ResetAssistCap();
|
||||
}
|
||||
}
|
||||
if(GetTarget() == mob)
|
||||
@@ -5677,3 +5682,11 @@ void Mob::SetCurrentSpeed(int in){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 Mob::GetMeleeMitigation() {
|
||||
int32 mitigation = 0;
|
||||
mitigation += spellbonuses.MeleeMitigationEffect;
|
||||
mitigation += itembonuses.MeleeMitigationEffect;
|
||||
mitigation += aabonuses.MeleeMitigationEffect;
|
||||
return mitigation;
|
||||
}
|
||||
+15
@@ -504,6 +504,10 @@ public:
|
||||
Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();}
|
||||
Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();}
|
||||
bool IsEngaged() { return(!hate_list.IsHateListEmpty()); }
|
||||
bool HasPrimaryAggro() { return PrimaryAggro; }
|
||||
bool HasAssistAggro() { return AssistAggro; }
|
||||
void SetPrimaryAggro(bool value) { PrimaryAggro = value; if (value) AssistAggro = false; }
|
||||
void SetAssistAggro(bool value) { AssistAggro = value; if (PrimaryAggro) AssistAggro = false; }
|
||||
bool HateSummon();
|
||||
void FaceTarget(Mob* MobToFace = 0);
|
||||
void SetHeading(float iHeading) { if(m_Position.w != iHeading) { pLastChange = Timer::GetCurrentTime();
|
||||
@@ -748,6 +752,7 @@ public:
|
||||
inline bool GetInvul(void) { return invulnerable; }
|
||||
inline void SetExtraHaste(int Haste) { ExtraHaste = Haste; }
|
||||
virtual int GetHaste();
|
||||
int32 GetMeleeMitigation();
|
||||
|
||||
uint8 GetWeaponDamageBonus(const Item_Struct* weapon, bool offhand = false);
|
||||
uint16 GetDamageTable(SkillUseTypes skillinuse);
|
||||
@@ -993,6 +998,11 @@ public:
|
||||
void ApplyAABonuses(const AA::Rank &rank, StatBonuses* newbon);
|
||||
bool CheckAATimer(int timer);
|
||||
|
||||
int NPCAssistCap() { return npc_assist_cap; }
|
||||
void AddAssistCap() { ++npc_assist_cap; }
|
||||
void DelAssistCap() { --npc_assist_cap; }
|
||||
void ResetAssistCap() { npc_assist_cap = 0; }
|
||||
|
||||
protected:
|
||||
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special = 0);
|
||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||
@@ -1293,6 +1303,11 @@ protected:
|
||||
glm::vec4 m_CurrentWayPoint;
|
||||
int cur_wp_pause;
|
||||
|
||||
bool PrimaryAggro;
|
||||
bool AssistAggro;
|
||||
int npc_assist_cap;
|
||||
Timer assist_cap_timer; // clear assist cap so more nearby mobs can be called for help
|
||||
|
||||
|
||||
int patrol;
|
||||
glm::vec3 m_FearWalkTarget;
|
||||
|
||||
+5
-1
@@ -1735,8 +1735,10 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
|
||||
if (iYellForHelp) {
|
||||
if(IsPet()) {
|
||||
GetOwner()->AI_Event_Engaged(attacker, iYellForHelp);
|
||||
} else {
|
||||
} else if (!HasAssistAggro() && NPCAssistCap() < RuleI(Combat, NPCAssistCap)) {
|
||||
entity_list.AIYellForHelp(this, attacker);
|
||||
if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled())
|
||||
assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1787,6 +1789,8 @@ void Mob::AI_Event_NoLongerEngaged() {
|
||||
|
||||
if(IsNPC())
|
||||
{
|
||||
SetPrimaryAggro(false);
|
||||
SetAssistAggro(false);
|
||||
if(CastToNPC()->GetCombatEvent() && GetHP() > 0)
|
||||
{
|
||||
if(entity_list.GetNPCByID(this->GetID()))
|
||||
|
||||
+58
-1
@@ -712,8 +712,18 @@ bool NPC::Process()
|
||||
}
|
||||
|
||||
//Handle assists...
|
||||
if(assist_timer.Check() && IsEngaged() && !Charmed()) {
|
||||
if (assist_cap_timer.Check()) {
|
||||
if (NPCAssistCap() > 0)
|
||||
DelAssistCap();
|
||||
else
|
||||
assist_cap_timer.Disable();
|
||||
}
|
||||
|
||||
if (assist_timer.Check() && IsEngaged() && !Charmed() && !HasAssistAggro() &&
|
||||
NPCAssistCap() < RuleI(Combat, NPCAssistCap)) {
|
||||
entity_list.AIYellForHelp(this, GetTarget());
|
||||
if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled())
|
||||
assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer));
|
||||
}
|
||||
|
||||
if(qGlobals)
|
||||
@@ -833,6 +843,53 @@ bool NPC::DatabaseCastAccepted(int spell_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NPC::SpawnZoneController(){
|
||||
|
||||
if (!RuleB(Zone, UseZoneController))
|
||||
return false;
|
||||
|
||||
NPCType* npc_type = new NPCType;
|
||||
memset(npc_type, 0, sizeof(NPCType));
|
||||
|
||||
strncpy(npc_type->name, "zone_controller", 60);
|
||||
npc_type->cur_hp = 2000000000;
|
||||
npc_type->max_hp = 2000000000;
|
||||
npc_type->hp_regen = 100000000;
|
||||
npc_type->race = 240;
|
||||
npc_type->gender = 2;
|
||||
npc_type->class_ = 1;
|
||||
npc_type->deity = 1;
|
||||
npc_type->level = 200;
|
||||
npc_type->npc_id = ZONE_CONTROLLER_NPC_ID;
|
||||
npc_type->loottable_id = 0;
|
||||
npc_type->texture = 3;
|
||||
npc_type->runspeed = 0;
|
||||
npc_type->d_melee_texture1 = 0;
|
||||
npc_type->d_melee_texture2 = 0;
|
||||
npc_type->merchanttype = 0;
|
||||
npc_type->bodytype = 11;
|
||||
|
||||
npc_type->prim_melee_type = 28;
|
||||
npc_type->sec_melee_type = 28;
|
||||
|
||||
npc_type->findable = 0;
|
||||
npc_type->trackable = 0;
|
||||
|
||||
strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1");
|
||||
|
||||
glm::vec4 point;
|
||||
point.x = 5000;
|
||||
point.y = 5000;
|
||||
point.z = -5000;
|
||||
|
||||
NPC* npc = new NPC(npc_type, nullptr, point, FlyMode3);
|
||||
npc->GiveNPCTypeData(npc_type);
|
||||
|
||||
entity_list.AddNPC(npc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client) {
|
||||
if(spawncommand == 0 || spawncommand[0] == 0) {
|
||||
return 0;
|
||||
|
||||
@@ -96,6 +96,7 @@ class NPC : public Mob
|
||||
{
|
||||
public:
|
||||
static NPC* SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client = nullptr);
|
||||
static bool SpawnZoneController();
|
||||
static int8 GetAILevel(bool iForceReRead = false);
|
||||
|
||||
NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false);
|
||||
|
||||
@@ -8490,6 +8490,524 @@ XS(XS_Mob_IsBlind) {
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_SeeInvisible);
|
||||
XS(XS_Mob_SeeInvisible) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::SeeInvisible(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->SeeInvisible();
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_SeeInvisibleUndead);
|
||||
XS(XS_Mob_SeeInvisibleUndead) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::SeeInvisibleUndead(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->SeeInvisibleUndead();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_SeeHide);
|
||||
XS(XS_Mob_SeeHide) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::SeeHide(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->SeeHide();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_SeeImprovedHide);
|
||||
XS(XS_Mob_SeeImprovedHide) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::SeeImprovedHide(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->SeeImprovedHide();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetNimbusEffect1);
|
||||
XS(XS_Mob_GetNimbusEffect1) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect1(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetNimbusEffect1();
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetNimbusEffect2);
|
||||
XS(XS_Mob_GetNimbusEffect2) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect2(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetNimbusEffect2();
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetNimbusEffect3);
|
||||
XS(XS_Mob_GetNimbusEffect3) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect3(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
uint8 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetNimbusEffect3();
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_IsTargetable);
|
||||
XS(XS_Mob_IsTargetable) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::IsTargetable(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsTargetable();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_HasShieldEquiped);
|
||||
XS(XS_Mob_HasShieldEquiped) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::HasShieldEquiped(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->HasShieldEquiped();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_HasTwoHandBluntEquiped);
|
||||
XS(XS_Mob_HasTwoHandBluntEquiped) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::HasTwoHandBluntEquiped(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->HasTwoHandBluntEquiped();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_HasTwoHanderEquipped);
|
||||
XS(XS_Mob_HasTwoHanderEquipped) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::HasTwoHanderEquipped(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->HasTwoHanderEquipped();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetHerosForgeModel);
|
||||
XS(XS_Mob_GetHerosForgeModel) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetHerosForgeModel(THIS, material_slot)");
|
||||
{
|
||||
Mob* THIS;
|
||||
int32 RETVAL;
|
||||
uint8 material_slot = (uint8)SvUV(ST(1));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetHerosForgeModel(material_slot);
|
||||
XSprePUSH;
|
||||
PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_IsEliteMaterialItem);
|
||||
XS(XS_Mob_IsEliteMaterialItem) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::IsEliteMaterialItem(THIS, material_slot)");
|
||||
{
|
||||
Mob* THIS;
|
||||
uint32 RETVAL;
|
||||
uint8 material_slot = (uint8)SvUV(ST(1));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsEliteMaterialItem(material_slot);
|
||||
XSprePUSH;
|
||||
PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetBaseSize);
|
||||
XS(XS_Mob_GetBaseSize) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetBaseSize(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
float RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetBaseSize();
|
||||
XSprePUSH;
|
||||
PUSHn((double)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_HasOwner);
|
||||
XS(XS_Mob_HasOwner) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::HasOwner(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->HasOwner();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_IsPet);
|
||||
XS(XS_Mob_IsPet) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::IsPet(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsPet();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_HasPet);
|
||||
XS(XS_Mob_HasPet) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::HasPet(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->HasPet();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_IsSilenced);
|
||||
XS(XS_Mob_IsSilenced) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::IsSilenced(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsSilenced();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_IsAmnesiad);
|
||||
XS(XS_Mob_IsAmnesiad) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::IsAmnesiad(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
bool RETVAL;
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsAmnesiad();
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetMeleeMitigation);
|
||||
XS(XS_Mob_GetMeleeMitigation) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetMeleeMitigation(THIS)");
|
||||
{
|
||||
Mob* THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob*, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetMeleeMitigation();
|
||||
XSprePUSH;
|
||||
PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
@@ -8803,6 +9321,26 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsFeared"), XS_Mob_IsFeared, file, "$");
|
||||
newXSproto(strcpy(buf, "IsBlind"), XS_Mob_IsBlind, file, "$");
|
||||
newXSproto(strcpy(buf, "SeeInvisible"), XS_Mob_SeeInvisible, file, "$");
|
||||
newXSproto(strcpy(buf, "SeeInvisibleUndead"), XS_Mob_SeeInvisibleUndead, file, "$");
|
||||
newXSproto(strcpy(buf, "SeeHide"), XS_Mob_SeeHide, file, "$");
|
||||
newXSproto(strcpy(buf, "SeeImprovedHide"), XS_Mob_SeeImprovedHide, file, "$");
|
||||
newXSproto(strcpy(buf, "GetNimbusEffect1"), XS_Mob_GetNimbusEffect1, file, "$");
|
||||
newXSproto(strcpy(buf, "GetNimbusEffect2"), XS_Mob_GetNimbusEffect2, file, "$");
|
||||
newXSproto(strcpy(buf, "GetNimbusEffect3"), XS_Mob_GetNimbusEffect3, file, "$");
|
||||
newXSproto(strcpy(buf, "IsTargetable"), XS_Mob_IsTargetable, file, "$");
|
||||
newXSproto(strcpy(buf, "HasShieldEquiped"), XS_Mob_HasShieldEquiped, file, "$");
|
||||
newXSproto(strcpy(buf, "HasTwoHandBluntEquiped"), XS_Mob_HasTwoHandBluntEquiped, file, "$");
|
||||
newXSproto(strcpy(buf, "HasTwoHanderEquipped"), XS_Mob_HasTwoHanderEquipped, file, "$");
|
||||
newXSproto(strcpy(buf, "GetHerosForgeModel"), XS_Mob_GetHerosForgeModel, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsEliteMaterialItem"), XS_Mob_IsEliteMaterialItem, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetBaseSize"), XS_Mob_GetBaseSize, file, "$");
|
||||
newXSproto(strcpy(buf, "HasOwner"), XS_Mob_HasOwner, file, "$");
|
||||
newXSproto(strcpy(buf, "IsPet"), XS_Mob_IsPet, file, "$");
|
||||
newXSproto(strcpy(buf, "HasPet"), XS_Mob_HasPet, file, "$");
|
||||
newXSproto(strcpy(buf, "IsSilenced"), XS_Mob_IsSilenced, file, "$");
|
||||
newXSproto(strcpy(buf, "IsAmnesiad"), XS_Mob_IsAmnesiad, file, "$");
|
||||
newXSproto(strcpy(buf, "GetMeleeMitigation"), XS_Mob_GetMeleeMitigation, file, "$");
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -484,10 +484,17 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string
|
||||
|
||||
//second look for /quests/zone/npcname.ext (precedence)
|
||||
const NPCType *npc_type = database.LoadNPCTypesData(npcid);
|
||||
if(!npc_type) {
|
||||
if (!npc_type && npcid != ZONE_CONTROLLER_NPC_ID) {
|
||||
return nullptr;
|
||||
}
|
||||
std::string npc_name = npc_type->name;
|
||||
|
||||
std::string npc_name;
|
||||
if (npcid == ZONE_CONTROLLER_NPC_ID){
|
||||
npc_name = "zone_controller";
|
||||
}
|
||||
else{
|
||||
npc_name = npc_type->name;
|
||||
}
|
||||
int sz = static_cast<int>(npc_name.length());
|
||||
for(int i = 0; i < sz; ++i) {
|
||||
if(npc_name[i] == '`') {
|
||||
|
||||
@@ -2598,6 +2598,29 @@ void QuestManager::UpdateInstanceTimer(uint16 instance_id, uint32 new_duration)
|
||||
}
|
||||
}
|
||||
|
||||
uint32 QuestManager::GetInstanceTimer() {
|
||||
if (zone && zone->GetInstanceID() > 0 && zone->GetInstanceTimer()) {
|
||||
uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime();
|
||||
return ttime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 QuestManager::GetInstanceTimerByID(uint16 instance_id) {
|
||||
if (instance_id == 0)
|
||||
return 0;
|
||||
|
||||
std::string query = StringFormat("SELECT ((start_time + duration) - UNIX_TIMESTAMP()) AS `remaining` FROM `instance_list` WHERE `id` = %lu", (unsigned long)instance_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
if (results.Success()) {
|
||||
auto row = results.begin();
|
||||
uint32 timer = atoi(row[0]);
|
||||
return timer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 QuestManager::GetInstanceID(const char *zone, int16 version)
|
||||
{
|
||||
QuestManagerCurrentQuestVars();
|
||||
@@ -3070,3 +3093,75 @@ std::string QuestManager::GetEncounter() const {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void QuestManager::UpdateZoneHeader(std::string type, std::string value) {
|
||||
if (strcasecmp(type.c_str(), "ztype") == 0)
|
||||
zone->newzone_data.ztype = atoi(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "fog_red") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.fog_red[i] = atoi(value.c_str());
|
||||
}
|
||||
} else if (strcasecmp(type.c_str(), "fog_green") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.fog_green[i] = atoi(value.c_str());
|
||||
}
|
||||
} else if (strcasecmp(type.c_str(), "fog_blue") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.fog_blue[i] = atoi(value.c_str());
|
||||
}
|
||||
} else if (strcasecmp(type.c_str(), "fog_minclip") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.fog_minclip[i] = atof(value.c_str());
|
||||
}
|
||||
} else if (strcasecmp(type.c_str(), "fog_maxclip") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.fog_maxclip[i] = atof(value.c_str());
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(type.c_str(), "gravity") == 0)
|
||||
zone->newzone_data.gravity = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "time_type") == 0)
|
||||
zone->newzone_data.time_type = atoi(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "rain_chance") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.rain_chance[i] = atoi(value.c_str());
|
||||
}
|
||||
} else if (strcasecmp(type.c_str(), "rain_duration") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.rain_duration[i] = atoi(value.c_str());
|
||||
}
|
||||
} else if (strcasecmp(type.c_str(), "snow_chance") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.snow_chance[i] = atoi(value.c_str());
|
||||
}
|
||||
} else if (strcasecmp(type.c_str(), "snow_duration") == 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
zone->newzone_data.snow_duration[i] = atoi(value.c_str());
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(type.c_str(), "sky") == 0)
|
||||
zone->newzone_data.sky = atoi(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "safe_x") == 0)
|
||||
zone->newzone_data.safe_x = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "safe_y") == 0)
|
||||
zone->newzone_data.safe_y = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "safe_z") == 0)
|
||||
zone->newzone_data.safe_z = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "max_z") == 0)
|
||||
zone->newzone_data.max_z = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "underworld") == 0)
|
||||
zone->newzone_data.underworld = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "minclip") == 0)
|
||||
zone->newzone_data.minclip = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "maxclip") == 0)
|
||||
zone->newzone_data.maxclip = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "fog_density") == 0)
|
||||
zone->newzone_data.fog_density = atof(value.c_str());
|
||||
else if (strcasecmp(type.c_str(), "suspendbuffs") == 0)
|
||||
zone->newzone_data.SuspendBuffs = atoi(value.c_str());
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct));
|
||||
memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size);
|
||||
entity_list.QueueClients(0, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -218,6 +218,9 @@ public:
|
||||
uint32 MerchantCountItem(uint32 NPCid, uint32 itemid);
|
||||
uint16 CreateInstance(const char *zone, int16 version, uint32 duration);
|
||||
void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration);
|
||||
void UpdateZoneHeader(std::string type, std::string value);
|
||||
uint32 GetInstanceTimer();
|
||||
uint32 GetInstanceTimerByID(uint16 instance_id = 0);
|
||||
void DestroyInstance(uint16 instance_id);
|
||||
uint16 GetInstanceID(const char *zone, int16 version);
|
||||
void AssignToInstance(uint16 instance_id);
|
||||
|
||||
@@ -549,6 +549,8 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spa
|
||||
spawn2_list.Insert(new_spawn);
|
||||
}
|
||||
|
||||
NPC::SpawnZoneController();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+18
-9
@@ -166,25 +166,34 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme
|
||||
else
|
||||
{
|
||||
ItemInst *old_aug = nullptr;
|
||||
const uint32 id = auged_with->GetID();
|
||||
bool isSolvent = auged_with->GetItem()->ItemType == ItemUseTypes::ItemTypeAugmentationSolvent;
|
||||
if (!isSolvent && auged_with->GetItem()->ItemType != ItemUseTypes::ItemTypeAugmentationDistiller)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Player tried to remove an augment without a solvent or distiller.");
|
||||
user->Message(13, "Error: Missing an augmentation solvent or distiller for removing this augment.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_slot);
|
||||
if(aug) {
|
||||
if (aug) {
|
||||
if (!isSolvent && auged_with->GetItem()->ID != aug->GetItem()->AugDistiller)
|
||||
{
|
||||
Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", auged_with->GetItem()->ID, aug->GetItem()->AugDistiller);
|
||||
user->Message(13, "Error: Wrong augmentation distiller for safely removing this augment.");
|
||||
return;
|
||||
}
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(aug);
|
||||
parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args);
|
||||
|
||||
args.assign(1, tobe_auged);
|
||||
bool destroyed = false;
|
||||
if(id == 40408 || id == 40409 || id == 40410) {
|
||||
destroyed = true;
|
||||
}
|
||||
|
||||
args.push_back(&destroyed);
|
||||
args.push_back(&isSolvent);
|
||||
|
||||
parse->EventItem(EVENT_AUGMENT_REMOVE, user, aug, nullptr, "", slot, &args);
|
||||
}
|
||||
|
||||
if(id == 40408 || id == 40409 || id == 40410)
|
||||
if (isSolvent)
|
||||
tobe_auged->DeleteAugment(in_augment->augment_slot);
|
||||
else
|
||||
old_aug = tobe_auged->RemoveAugment(in_augment->augment_slot);
|
||||
|
||||
Reference in New Issue
Block a user