mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-10 02:31:03 +00:00
major updates
optimized pet support perl support
This commit is contained in:
@@ -45,6 +45,8 @@ enum : int { //values for pTimerType
|
||||
pTimerLinkedSpellReuseStart = 28,
|
||||
pTimerLinkedSpellReuseEnd = 48,
|
||||
|
||||
pTimerShieldAbility = 86,
|
||||
|
||||
pTimerLayHands = 87, //these IDs are used by client too
|
||||
pTimerHarmTouch = 89, //so dont change them
|
||||
|
||||
|
||||
+1
-1
@@ -572,7 +572,7 @@ typedef enum {
|
||||
#define SE_FleshToBone 207 // implemented
|
||||
//#define SE_PurgePoison 208 // not used
|
||||
#define SE_DispelBeneficial 209 // implemented
|
||||
//#define SE_PetShield 210 // *not implemented
|
||||
#define SE_PetShield 210 // implmented, @Shiedling, allows pet to 'shield' owner for 50 pct of damage taken for a duration, base: 1 (Time multiplier 1=12 seconds, 2=24 ect), limit: mitigation on pet owner override (not on live), max: mitigation on pet overide (not on live)
|
||||
#define SE_AEMelee 211 // implemented TO DO: Implement to allow NPC use (client only atm).
|
||||
#define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana.
|
||||
#define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet
|
||||
|
||||
+19
-24
@@ -1691,6 +1691,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill
|
||||
InterruptSpell();
|
||||
SetPet(0);
|
||||
SetHorseId(0);
|
||||
ShieldAbilityClearVariables();
|
||||
dead = true;
|
||||
|
||||
if (GetMerc()) {
|
||||
@@ -2252,6 +2253,8 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQ::skills::SkillTy
|
||||
Log(Logs::Detail, Logs::Attack, "%s Mobs currently Aggro %i", __FUNCTION__, zone->MobsAggroCount());
|
||||
}
|
||||
|
||||
ShieldAbilityClearVariables();
|
||||
|
||||
SetHP(0);
|
||||
SetPet(0);
|
||||
|
||||
@@ -5278,61 +5281,53 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
|
||||
|
||||
hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + (defender->GetFcDamageAmtIncoming(this, 0, true, hit.skill));
|
||||
|
||||
Shout("Shielder ID [%i]", defender->GetShielderID());
|
||||
|
||||
if (defender->GetShielderID()) {
|
||||
hit.damage_done = hit.damage_done * 50 / 100;//Don't round.
|
||||
DoShieldDamageOnShielder(defender, hit.damage_done, hit.skill);
|
||||
hit.damage_done -= hit.damage_done * defender->GetShieldTargetMitigation() / 100; //Default shielded takes 50 pct damage
|
||||
}
|
||||
|
||||
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
|
||||
}
|
||||
|
||||
void Mob::DoShieldDamageOnShielder(Mob* shielder_target, int hit_damage_done, EQ::skills::SkillType skillInUse)
|
||||
void Mob::DoShieldDamageOnShielder(Mob* shield_target, int hit_damage_done, EQ::skills::SkillType skillInUse)
|
||||
{
|
||||
if (!shielder_target) {
|
||||
if (!shield_target) {
|
||||
return;
|
||||
}
|
||||
|
||||
Mob *shielder = entity_list.GetMob(shielder_target->GetShielderID());
|
||||
Mob *shielder = entity_list.GetMob(shield_target->GetShielderID());
|
||||
|
||||
if (!shielder) {
|
||||
return;
|
||||
}
|
||||
|
||||
//AA to increase SPA 230 extended shielding
|
||||
int max_shielder_distance = 15;
|
||||
int distance_mod = aabonuses.ExtendedShielding + itembonuses.ExtendedShielding + spellbonuses.ExtendedShielding;
|
||||
max_shielder_distance += max_shielder_distance * distance_mod / 100;
|
||||
max_shielder_distance = std::max(max_shielder_distance, 0);
|
||||
|
||||
if (shielder_target->CalculateDistance(shielder->GetX(), shielder->GetY(), shielder->GetZ()) > static_cast<float>(max_shielder_distance)) {
|
||||
//Clear variables Shield end
|
||||
Shout("Clear variables shield end");
|
||||
if (shield_target->CalculateDistance(shielder->GetX(), shielder->GetY(), shielder->GetZ()) > static_cast<float>(shielder->GetMaxShielderDistance())) {
|
||||
shielder->SetShieldTargetID(0);
|
||||
shielder_target->SetShielderID(0);
|
||||
shielder->SetShielderMitigation(0);
|
||||
shielder->SetShielerMaxDistance(0);
|
||||
shielder->shield_timer.Disable();
|
||||
shield_target->SetShielderID(0);
|
||||
shield_target->SetShieldTargetMitigation(0);
|
||||
return; //Too far away, no message is given thoughh.
|
||||
}
|
||||
|
||||
int mitigation = 75;
|
||||
int mitigation = shielder->GetShielderMitigation(); //Default shielder mitigates 25 pct of damage taken, this can be increased up to max 50 by equiping a shield item
|
||||
|
||||
if (shielder->HasShieldEquiped() && shielder->IsClient()) {
|
||||
if (shielder->IsClient() && shielder->HasShieldEquiped()) {
|
||||
|
||||
EQ::ItemInstance* inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotSecondary);
|
||||
EQ::ItemInstance* inst = shielder->CastToClient()->GetInv().GetItem(EQ::invslot::slotSecondary);
|
||||
|
||||
if (inst) {
|
||||
|
||||
const EQ::ItemData* shield = inst->GetItem();
|
||||
if (shield && shield->ItemType == EQ::item::ItemTypeShield) {
|
||||
mitigation -= shield->AC * 0.50; //1% increase per 2 AC
|
||||
mitigation += shield->AC * 50 / 100; //1% increase per 2 AC
|
||||
std::min(50, mitigation);//50 pct max mitigation bonus from /shield
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mitigation = std::max(mitigation, 50);
|
||||
|
||||
hit_damage_done = hit_damage_done * mitigation / 100;
|
||||
|
||||
hit_damage_done -= hit_damage_done * mitigation / 100;
|
||||
shielder->Damage(this, hit_damage_done, SPELL_UNKNOWN, skillInUse, true, -1, false, m_specialattacks);
|
||||
shielder->CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
|
||||
}
|
||||
|
||||
+47
-32
@@ -12804,14 +12804,30 @@ void Client::Handle_OP_SetTitle(const EQApplicationPacket *app)
|
||||
|
||||
void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
||||
{
|
||||
/*
|
||||
/shield command mechanics
|
||||
Warriors get this skill at level 30
|
||||
Used by typing /shield while targeting a player
|
||||
While active for the duration of 12 seconds baseline. The 'shield target' will take 50 pct less damage and
|
||||
the 'shielder' will be hit with the damage taken by the 'shield target' after all applicable mitigiont is calculated,
|
||||
the damage on the 'shielder' will be reduced by 25 percent, this reduction can be increased to 50 pct if equiping a shield.
|
||||
You receive a 1% increase in mitigation for every 2 AC on the shield.
|
||||
Shielder must stay with in a close distance (15 units) to your 'shield target'. If either move out of range, shield ends, no message given.
|
||||
Both duration and shield range can be modified by AA.
|
||||
Recast is 3 minutes.
|
||||
|
||||
For custom use cases, Mob::ShieldAbility can be used in quests with all parameters being altered. This functional
|
||||
is also used for SPA 201 SE_PetShield, which functions in a simalar manner with pet shielding owner.
|
||||
|
||||
Note: If either the shielder or the shield target die all variables are reset on both.
|
||||
|
||||
*/
|
||||
|
||||
if (app->size != sizeof(Shielding_Struct)) {
|
||||
LogError("OP size error: OP_Shielding expected:[{}] got:[{}]", sizeof(Shielding_Struct), app->size);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: Defensive makes it not cast?
|
||||
//TODO: Bankers ect don't let you shjield 6826 You can not perform shielding while you are speaking with a banker, a merchant, or a guildmaster.
|
||||
|
||||
if (GetLevel() < 30) { //Client gives message
|
||||
return;
|
||||
}
|
||||
@@ -12820,20 +12836,24 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
pTimerType timer = pTimerShieldAbility;
|
||||
|
||||
if (!p_timers.Expired(&database, timer, false)) {
|
||||
uint32 remain = p_timers.GetRemainingTime(timer);
|
||||
Message(Chat::White, "You can use the ability /shield in %d minutes %d seconds.", ((remain) / 60), (remain % 60));
|
||||
return;
|
||||
}
|
||||
|
||||
Shielding_Struct* shield = (Shielding_Struct*)app->pBuffer;
|
||||
|
||||
Mob* shield_target = entity_list.GetMob(shield->target_id);
|
||||
|
||||
Shout("PACKET Shielder %i", shield_target->GetShielderID());
|
||||
Shout("PACKET Shield Target %i", GetShieldTargetID());
|
||||
|
||||
if (!shield_target) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (shield_target->IsNPC()) {
|
||||
//You must first target a living player //TODO Find string
|
||||
MessageString(Chat::White, SHIELD_TARGET_NPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12841,48 +12861,43 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
//Does 'Shield Target' already have a 'Shielder'
|
||||
if (shield_target->GetShielderID() == GetID()) {
|
||||
//You are a 'Shield Target' already have a 'Shielder'
|
||||
if (GetShielderID() || shield_target->GetShielderID()) {
|
||||
MessageString(Chat::White, ALREADY_SHIELDED);
|
||||
return;
|
||||
}
|
||||
|
||||
//Does 'Shielder' already have a 'Shield Target'
|
||||
if (GetShieldTargetID() == GetID()) {
|
||||
MessageString(Chat::White, ALREADY_SHIELDED);
|
||||
//You are being shielded or already have a 'Shield Target'
|
||||
if (GetShieldTargetID() || shield_target->GetShieldTargetID()) {
|
||||
MessageString(Chat::White, ALREADY_SHIELDING);
|
||||
return;
|
||||
}
|
||||
//AA to increase SPA 230 extended shielding
|
||||
|
||||
int max_shielder_distance = 15;
|
||||
int distance_mod = aabonuses.ExtendedShielding + itembonuses.ExtendedShielding + spellbonuses.ExtendedShielding;
|
||||
max_shielder_distance += max_shielder_distance * distance_mod / 100;
|
||||
max_shielder_distance = std::max(max_shielder_distance, 0);
|
||||
|
||||
if (shield_target->CalculateDistance(GetX(), GetY(), GetZ()) > static_cast<float>(max_shielder_distance)) {
|
||||
//AA to increase SPA 230 extended shielding
|
||||
int max_shlder_distance = 15;
|
||||
max_shlder_distance += aabonuses.ExtendedShielding + itembonuses.ExtendedShielding + spellbonuses.ExtendedShielding;
|
||||
max_shlder_distance = std::max(max_shlder_distance, 0);
|
||||
|
||||
if (shield_target->CalculateDistance(GetX(), GetY(), GetZ()) > static_cast<float>(max_shlder_distance)) {
|
||||
return; //Too far away, no message is given thoughh.
|
||||
}
|
||||
|
||||
entity_list.MessageCloseString(this, false, 100, 0, START_SHIELDING, GetName(), shield_target->GetName());
|
||||
|
||||
//Apply to Shielder
|
||||
//shield_ability.shield_target_id = shield_target->GetID();
|
||||
|
||||
//Apply to Shield Target
|
||||
//shield_target->shield_ability.shielder_id = GetID();
|
||||
|
||||
SetShieldTargetID(shield_target->GetID());
|
||||
SetShielderMitigation(25);
|
||||
SetShielerMaxDistance(max_shlder_distance);
|
||||
|
||||
shield_target->SetShielderID(GetID());
|
||||
|
||||
|
||||
shield_target->SetShieldTargetMitigation(50);
|
||||
|
||||
//Calculate AA for adding time SPA 255 extend shield duration
|
||||
int shield_duration = 12000;
|
||||
Shout("1 Duration %i", shield_duration);
|
||||
shield_duration += (aabonuses.ShieldDuration + itembonuses.ShieldDuration + spellbonuses.ShieldDuration) * 1000;
|
||||
Shout("2 Duration %i", shield_duration);
|
||||
shield_duration = std::max(shield_duration, 1); //Incase of negative modifiers lets just make min duration 1 ms.
|
||||
Shout("3 Duration %i", shield_duration);
|
||||
shield_timer.Start(shield_duration);
|
||||
shield_timer.Start(static_cast<uint32>(shield_duration));
|
||||
|
||||
p_timers.Start(timer, SHIELD_ABILITY_RECAST_TIME);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -461,14 +461,7 @@ bool Client::Process() {
|
||||
}
|
||||
|
||||
if (shield_timer.Check()) {
|
||||
Mob * shield_target = entity_list.GetMob(GetShieldTargetID());
|
||||
|
||||
if (shield_target) {
|
||||
entity_list.MessageCloseString(this, false, 100, 0, END_SHIELDING, GetCleanName(), shield_target->GetCleanName());
|
||||
}
|
||||
shield_timer.Disable();
|
||||
SetShieldTargetID(0);
|
||||
shield_target->SetShielderID(0);
|
||||
ShieldAbilityFinish();
|
||||
}
|
||||
|
||||
SpellProcess();
|
||||
|
||||
+2
-1
@@ -105,6 +105,8 @@
|
||||
|
||||
#define AURA_HARDCAP 2
|
||||
|
||||
#define SHIELD_ABILITY_RECAST_TIME 180
|
||||
|
||||
typedef enum { //focus types
|
||||
focusSpellHaste = 1, //@Fc, SPA: 127, SE_IncreaseSpellHaste, On Caster, cast time mod pct, base: pct
|
||||
focusSpellDuration, //@Fc, SPA: 128, SE_IncreaseSpellDuration, On Caster, spell duration mod pct, base: pct
|
||||
@@ -544,7 +546,6 @@ struct StatBonuses {
|
||||
int32 Pet_Crit_Melee_Damage_Pct_Owner; // base = percent mod for pet critcal damage from owner
|
||||
int32 Pet_Add_Atk; // base = Pet ATK bonus from owner
|
||||
|
||||
|
||||
// AAs
|
||||
int32 ShieldDuration; // extends duration of /shield ability
|
||||
int32 ExtendedShielding; // extends range of /shield ability
|
||||
|
||||
+101
@@ -378,6 +378,9 @@ Mob::Mob(
|
||||
shield_timer.Disable();
|
||||
shield_target_id = 0;
|
||||
shielder_id = 0;
|
||||
shield_target_mitigation = 0;
|
||||
shielder_mitigation = 0;
|
||||
shielder_max_distance = 0;
|
||||
|
||||
destructibleobject = false;
|
||||
wandertype = 0;
|
||||
@@ -6118,6 +6121,104 @@ float Mob::GetDefaultRaceSize() const {
|
||||
return GetRaceGenderDefaultHeight(race, gender);
|
||||
}
|
||||
|
||||
void Mob::ShieldAbility(uint32 target_id, int max_shlder_distance, int shield_duration, int shld_target_mitigation, int shlder_mitigation)
|
||||
{
|
||||
|
||||
Mob* shield_target = entity_list.GetMob(target_id);
|
||||
|
||||
if (!shield_target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shield_target->GetID() == GetID()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//You have a shielder, or your 'Shield Target' already has a 'Shielder'
|
||||
if (GetShielderID() || shield_target->GetShielderID()) {
|
||||
|
||||
if (IsClient()) {
|
||||
MessageString(Chat::White, ALREADY_SHIELDED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//You are being shielded or already have a 'Shield Target'
|
||||
if (GetShieldTargetID() || shield_target->GetShieldTargetID()) {
|
||||
|
||||
if (IsClient()) {
|
||||
MessageString(Chat::White, ALREADY_SHIELDING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (shield_target->CalculateDistance(GetX(), GetY(), GetZ()) > static_cast<float>(max_shlder_distance)) {
|
||||
if (IsClient()) {
|
||||
MessageString(Chat::White, TARGET_TOO_FAR); //Live doesn't give any message for failure, for the quest ability lets allow it.
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
entity_list.MessageCloseString(this, false, 100, 0, START_SHIELDING, GetCleanName(), shield_target->GetCleanName());
|
||||
|
||||
SetShieldTargetID(shield_target->GetID());
|
||||
SetShielderMitigation(shlder_mitigation);
|
||||
SetShielerMaxDistance(max_shlder_distance);
|
||||
|
||||
shield_target->SetShielderID(GetID());
|
||||
shield_target->SetShieldTargetMitigation(shld_target_mitigation);
|
||||
|
||||
shield_timer.Start(shield_duration);
|
||||
}
|
||||
|
||||
void Mob::ShieldAbilityFinish()
|
||||
{
|
||||
Mob* shield_target = entity_list.GetMob(GetShieldTargetID());
|
||||
|
||||
if (shield_target) {
|
||||
entity_list.MessageCloseString(this, false, 100, 0, END_SHIELDING, GetCleanName(), shield_target->GetCleanName());
|
||||
shield_target->SetShielderID(0);
|
||||
shield_target->SetShieldTargetMitigation(0);
|
||||
}
|
||||
SetShieldTargetID(0);
|
||||
SetShielderMitigation(0);
|
||||
SetShielerMaxDistance(0);
|
||||
shield_timer.Disable();
|
||||
}
|
||||
|
||||
void Mob::ShieldAbilityClearVariables()
|
||||
{
|
||||
//If 'shield target' dies
|
||||
if (GetShielderID()){
|
||||
|
||||
Mob* shielder = entity_list.GetMob(GetShielderID());
|
||||
|
||||
if (shielder) {
|
||||
shielder->SetShieldTargetID(0);
|
||||
shielder->SetShielderMitigation(0);
|
||||
shielder->SetShielerMaxDistance(0);
|
||||
shielder->shield_timer.Disable();
|
||||
}
|
||||
SetShielderID(0);
|
||||
SetShieldTargetMitigation(0);
|
||||
}
|
||||
|
||||
//If 'shielder' dies
|
||||
if (GetShieldTargetID()) {
|
||||
|
||||
Mob* shield_target = entity_list.GetMob(GetShieldTargetID());
|
||||
|
||||
if (shield_target) {
|
||||
shield_target->SetShielderID(0);
|
||||
shield_target->SetShieldTargetMitigation(0);
|
||||
}
|
||||
SetShieldTargetID(0);
|
||||
SetShielderMitigation(0);
|
||||
SetShielerMaxDistance(0);
|
||||
shield_timer.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
bool Mob::JoinHealRotationTargetPool(std::shared_ptr<HealRotation>* heal_rotation)
|
||||
{
|
||||
|
||||
+16
-4
@@ -1125,11 +1125,20 @@ public:
|
||||
|
||||
Trade* trade;
|
||||
|
||||
void ShieldAbility(uint32 target_id, int max_shlder_distance = 15, int shield_duration = 12000, int shld_target_mitigation = 50, int shlder_mitigation = 75);
|
||||
void DoShieldDamageOnShielder(Mob* shield_target, int hit_damage_done, EQ::skills::SkillType skillInUse);
|
||||
inline int GetShielderID() const { return shielder_id; }
|
||||
inline void SetShielderID(int ent_id) { shielder_id = ent_id; }
|
||||
inline int GetShieldTargetID() const { return shield_target_id; }
|
||||
inline void SetShieldTargetID(int ent_id) { shield_target_id = ent_id; }
|
||||
void ShieldAbilityFinish();
|
||||
void ShieldAbilityClearVariables();
|
||||
inline uint32 GetShielderID() const { return shielder_id; }
|
||||
inline void SetShielderID(uint32 val) { shielder_id = val; }
|
||||
inline uint32 GetShieldTargetID() const { return shield_target_id; }
|
||||
inline void SetShieldTargetID(uint32 val) { shield_target_id = val; }
|
||||
inline int GetShieldTargetMitigation() const { return shield_target_mitigation; }
|
||||
inline void SetShieldTargetMitigation(int val) { shield_target_mitigation = val; }
|
||||
inline int GetShielderMitigation() const { return shielder_mitigation; }
|
||||
inline void SetShielderMitigation(int val) { shielder_mitigation = val; }
|
||||
inline int GetMaxShielderDistance() const { return shielder_max_distance; }
|
||||
inline void SetShielerMaxDistance(int val) { shielder_max_distance = val; }
|
||||
|
||||
inline glm::vec4 GetCurrentWayPoint() const { return m_CurrentWayPoint; }
|
||||
inline float GetCWPP() const { return(static_cast<float>(cur_wp_pause)); }
|
||||
@@ -1433,6 +1442,9 @@ protected:
|
||||
Timer shield_timer;
|
||||
uint32 shield_target_id;
|
||||
uint32 shielder_id;
|
||||
int shield_target_mitigation;
|
||||
int shielder_mitigation;
|
||||
int shielder_max_distance;
|
||||
|
||||
//spell casting vars
|
||||
Timer spellend_timer;
|
||||
|
||||
@@ -1128,6 +1128,10 @@ void Mob::AI_Process() {
|
||||
if (focus_proc_limit_timer.Check())
|
||||
FocusProcLimitProcess();
|
||||
|
||||
if (shield_timer.Check()) {
|
||||
ShieldAbilityFinish();
|
||||
}
|
||||
|
||||
auto npcSpawnPoint = CastToNPC()->GetSpawnPoint();
|
||||
if (GetSpecialAbility(TETHER)) {
|
||||
float tether_range = static_cast<float>(GetSpecialAbilityParam(TETHER, 0));
|
||||
|
||||
+45
-40
@@ -4179,44 +4179,6 @@ XS(XS_Mob_GetResist) {
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetShieldTarget); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_GetShieldTarget) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetShieldTarget(THIS)"); // @categories Script Utility
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *RETVAL;
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
//RETVAL = THIS->GetShieldTarget();
|
||||
ST(0) = sv_newmortal();
|
||||
sv_setref_pv(ST(0), "Mob", (void *) RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_SetShieldTarget); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_SetShieldTarget) {
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::SetShieldTarget(THIS, mob)"); // @categories Script Utility
|
||||
{
|
||||
Mob *THIS;
|
||||
Mob *mob;
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV *) SvRV(ST(1)));
|
||||
mob = INT2PTR(Mob *, tmp);
|
||||
} else
|
||||
Perl_croak(aTHX_ "mob is not of type Mob");
|
||||
if (mob == nullptr)
|
||||
Perl_croak(aTHX_ "mob is nullptr, avoiding crash.");
|
||||
|
||||
//THIS->SetShieldTarget(mob);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_Charmed); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_Charmed) {
|
||||
dXSARGS;
|
||||
@@ -6301,6 +6263,50 @@ XS(XS_Mob_AddNimbusEffect) {
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_ShieldAbility); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_ShieldAbility) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 6)
|
||||
Perl_croak(aTHX_ "Usage: Mob::ShieldAbility(THIS, uint32 target_id, int32 max_shielder_distance, int32 shield_duration [ms]"); // @categories Spells and Disciplines
|
||||
{
|
||||
Mob *THIS;
|
||||
uint32 target_id = (uint32)SvUV(ST(1));
|
||||
int32 max_shlder_distance;
|
||||
int32 shld_duration;
|
||||
int32 shld_target_mitigation;
|
||||
int32 shlder_mitigation;
|
||||
|
||||
VALIDATE_THIS_IS_MOB;
|
||||
if (items < 3)
|
||||
max_shlder_distance = 15;
|
||||
else {
|
||||
max_shlder_distance = max_shlder_distance = (int32)SvUV(ST(2));
|
||||
}
|
||||
|
||||
if (items < 4)
|
||||
shld_duration = 12000;
|
||||
else {
|
||||
shld_duration = (int32)SvUV(ST(3));
|
||||
}
|
||||
|
||||
if (items < 5)
|
||||
shld_target_mitigation = 50;
|
||||
else {
|
||||
shld_target_mitigation = (int32)SvUV(ST(4));
|
||||
}
|
||||
|
||||
if (items < 6)
|
||||
shlder_mitigation = 50;
|
||||
else {
|
||||
shlder_mitigation = (int32)SvUV(ST(5));
|
||||
}
|
||||
|
||||
THIS->ShieldAbility(target_id, max_shlder_distance, shld_duration, shld_target_mitigation, shlder_mitigation);
|
||||
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
XS(XS_Mob_CastToBot); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_CastToBot)
|
||||
@@ -6561,8 +6567,6 @@ XS(boot_Mob) {
|
||||
newXSproto(strcpy(buf, "DontRootMeBefore"), XS_Mob_DontRootMeBefore, file, "$");
|
||||
newXSproto(strcpy(buf, "DontSnareMeBefore"), XS_Mob_DontSnareMeBefore, file, "$");
|
||||
newXSproto(strcpy(buf, "GetResist"), XS_Mob_GetResist, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetShieldTarget"), XS_Mob_GetShieldTarget, file, "$");
|
||||
newXSproto(strcpy(buf, "SetShieldTarget"), XS_Mob_SetShieldTarget, file, "$$");
|
||||
newXSproto(strcpy(buf, "Charmed"), XS_Mob_Charmed, file, "$");
|
||||
newXSproto(strcpy(buf, "GetLevelHP"), XS_Mob_GetLevelHP, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetZoneID"), XS_Mob_GetZoneID, file, "$");
|
||||
@@ -6672,6 +6676,7 @@ XS(boot_Mob) {
|
||||
newXSproto(strcpy(buf, "CanRaceEquipItem"), XS_Mob_CanRaceEquipItem, file, "$$");
|
||||
newXSproto(strcpy(buf, "RemoveAllNimbusEffects"), XS_Mob_RemoveAllNimbusEffects, file, "$");
|
||||
newXSproto(strcpy(buf, "AddNimbusEffect"), XS_Mob_AddNimbusEffect, file, "$$");
|
||||
newXSproto(strcpy(buf, "ShieldAbility"), XS_Mob_ShieldAbility, file, "$$$$$$");
|
||||
#ifdef BOTS
|
||||
newXSproto(strcpy(buf, "CastToBot"), XS_Mob_CastToBot, file, "$");
|
||||
#endif
|
||||
|
||||
@@ -2950,6 +2950,20 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_PetShield: {
|
||||
if (IsPet()) {
|
||||
Mob* petowner = GetOwner();
|
||||
if (petowner) {
|
||||
|
||||
int shield_duration = spells[spell_id].base[i] * 12 * 1000;
|
||||
int shld_target_mitigation = spells[spell_id].base2[i] ? spells[spell_id].base2[i] : 50;
|
||||
int shlder_mitigation = spells[spell_id].max[i] ? spells[spell_id].base2[i] : 50;
|
||||
ShieldAbility(petowner->GetID(), 25, shield_duration, shld_target_mitigation, shlder_mitigation);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_PersistentEffect:
|
||||
MakeAura(spell_id);
|
||||
break;
|
||||
|
||||
@@ -287,7 +287,9 @@
|
||||
#define SUSPEND_MINION_SUSPEND 3268 //%1 tells you, 'By your command, master.'
|
||||
#define ONLY_SUMMONED_PETS 3269 //3269 This effect only works with summoned pets.
|
||||
#define SUSPEND_MINION_FIGHTING 3270 //Your pet must be at peace, first.
|
||||
#define SHIELD_TARGET_NPC 3278 //You must first target a living Player Character.
|
||||
#define ALREADY_SHIELDED 3279 //Either you or your target is already being shielded.
|
||||
#define ALREADY_SHIELDING 3280 //Either you or your target is already shielding another.
|
||||
#define START_SHIELDING 3281 //%1 begins to use %2 as a living shield!
|
||||
#define END_SHIELDING 3282 //%1 ceases protecting %2.
|
||||
#define TRADESKILL_MISSING_ITEM 3455 //You are missing a %1.
|
||||
|
||||
Reference in New Issue
Block a user