Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Paul Coene
2016-01-02 09:17:09 -05:00
56 changed files with 2274 additions and 766 deletions
+11 -1
View File
@@ -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
View File
@@ -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;
}
}
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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;
+39
View File
@@ -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);
+10
View 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
View File
@@ -83,7 +83,8 @@ typedef enum {
EVENT_DEATH_COMPLETE,
EVENT_UNHANDLED_OPCODE,
EVENT_TICK,
EVENT_SPAWN_ZONE,
EVENT_DEATH_ZONE,
_LargestEventID
} QuestEventID;
+15 -1
View File
@@ -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
View File
@@ -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() {
+20
View File
@@ -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
View File
@@ -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;
+13
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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);
+538
View File
@@ -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;
}
+9 -2
View File
@@ -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] == '`') {
+95
View File
@@ -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);
}
+3
View File
@@ -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);
+2
View File
@@ -549,6 +549,8 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spa
spawn2_list.Insert(new_spawn);
}
NPC::SpawnZoneController();
return true;
}
+18 -9
View File
@@ -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);