EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Quests::Plugins & Mods (https://www.eqemulator.org/forums/forumdisplay.php?f=678)
-   -   Plugin::ArcheryAttack() (https://www.eqemulator.org/forums/showthread.php?t=30649)

nenelan 02-23-2010 10:14 PM

Plugin::ArcheryAttack()
 
Going to post it for now. May need more work, as I was unable to test the complete functionality for Hitting of All clients (couldn't set it up to connect more than one).

What this plugin will do is allow a mob to do a custom archery attack against either, Current Target, All Targets on hatelist, or a random target on the mob's hatelist.

Certain variables are settable in the main plugin file.

Plugin requires RandomRange() from the following link:
http://www.eqemulator.org/forums/showthread.php?t=30421

Here are the steps to add this plugin to your server:

1. Open notepad, or whatever text editor you prefer.

2. Copy and paste the following code into Notepad:

Code:

# Usage: plugin::ArcheryAttack(MeanDamage, Variance, TargNumber);
# MeanDamage - average damage of the attack
# Variance - +- % of mean as a range.
# TargNumber - 1: Current target, 2: All Targets on Hatelist, 3: Random Target from Hatelist
# Requires most current globals.pl and randomrange.pl plugins.

sub ArcheryAttack {

## Variables, set these to customize how the script works

$ACDiv = 75;    # 35% shielding (max default) at 2625 AC with ACDiv of 75
$PCTMiss = 5;    # Percent chance to miss outright
$PCTCrit = 5;    # Percent chance to critically hit
$MaxShield = 35; # Max Shielding percent
$ThroatDamage = 1.25; # Following variables edit the damage
$HeadDamage = 1.1;    # Based on where the arrow is striking
$ChestDamage = 1.0;  # Feel free to edit these to
$ArmDamage = 0.9;    # Suit your needs.
$LegDamage = 0.9;
$HandDamage = 0.75;
$FootDamage = 0.75;

## End Variables

$PCTMiss = 100-$PCTMiss+1;

        $npc = plugin::val('$npc');
        $entity_list = plugin::val('entity_list');

        my $MeanDamage = $_[0];
        my $Variance = $_[1];
        my $TargNumber = $_[2];
        my $MobName = $npc->GetCleanName();

        my $MinDamage = int ( $MeanDamage * (1-($Variance/100)) );
        my $MaxDamage = int ( $MeanDamage * (1+($Variance/100)) );
        $HitDmg = plugin::RandomRange($MinDamage, $MaxDamage);


        if ($TargNumber == 1) {
                      $targ = $npc->GetHateTop();
                $hitname = $targ->GetName();
                    $targid = $targ->GetID();
                $targid = $entity_list->GetClientByID($targid);
                LocDmg();
                quest::emote("sights and releases an arrow at his most infuriating enemy, $hitname.");
                quest::doanim(9);
                ApplyDamage();
        }

        if ($TargNumber == 2) {
                quest::emote("begins to a fire off a furious barrage of arrows, aiming at everyone around him!");
                quest::doanim(9);
                LocDmg();
                HitAllClients();
        }

        if ($TargNumber == 3) {
                $target = $npc->GetHateRandom();
                $targid = $target->GetID();
                $targid = $entity_list->GetClientByID($targid);
                $hitname = $target->GetName();
                LocDmg();       
                quest::emote("looses an arrow at $hitname at random.");
                quest::doanim(9);
                ApplyDamage();
        }
}

sub LocDmg {       

        $HitLoc = quest::ChooseRandom("head","head","leg","arm","chest","chest","throat","throat","hand","foot");

        CritOrMiss();

        if ($HitLoc eq "head") {
                $HitDmg = int($HitDmg*$HeadDamage);
        }

        if ($HitLoc eq "leg") {
                $HitDmg = int($HitDmg*$LegDamage);
        }

        if ($HitLoc eq "arm") {
                $HitDmg = int($HitDmg*$ArmDamage);
        }

        if ($HitLoc eq "throat") {
                $HitDmg = int($HitDmg*$ThroatDamage);
        }

        if ($HitLoc eq "hand" ) {
                $HitDmg = int($HitDmg*$HandDamage);
        }

        if ($HitLoc eq "foot") {
                $HitDmg = int($HitDmg*$FootDamage);
        }

        if ($HitLoc eq "chest") {
                $HitDmg = int($HitDmg*$ChestDamage);
        }
}


sub HitAllClients {       
        my @hatelist = $npc->GetHateList();
        foreach $ent (@hatelist)
        {
                if($ent)
                {
                        my $h_ent = $ent->GetEnt();
                        if($h_ent)
                        {
                                    $targid = $h_ent->GetID();
                                $targid = $entity_list->GetClientByID($targid);
                                ApplyDamage();
                        }
                }
        }
}

sub ApplyDamage {
        if ($HitDmg != 0) {

        $pac = $targid->CastToMob()->GetAC();

        $shielding = $pac/$ACDiv;


        if ($shielding > $MaxShield) {
                $shielding = $MaxShield;
        }

        $shielding = $shielding/100;
        $HitDmg = int ($HitDmg * (1-$shielding));
        $targid->Damage($npc,$HitDmg,0,4);
                if ($DidCrit eq "crit") {
                        $targid->Message(13,"You have been CRITICALLY STRUCK by an arrow in the $HitLoc for $HitDmg points of non-melee damage!"); 
                }
                else {
                        $targid->Message(13,"You have been struck by an arrow in the $HitLoc for $HitDmg points of non-melee damage!"); 
                }
        }
        else {
                $targid->Message(13,"You breathe a sigh of relief as the arrow narrowly misses you!");
        }
}

sub CritOrMiss {

        $didmiss = int(rand(100));
        if ($didmiss > $PCTMiss) {
                $HitDmg = 0;
        }
        if ($didmiss <= $PCTCrit) {
                $DidCrit = "crit";
                $HitDmg = $HitDmg*2;
        }

        else {
                $DidCrit = "no";
        }
}

3. Save that file to your server /plugins/ folder and name it "ArcheryAttack.pl".

4. Look over the variables in the ArcheryAttack.pl that you just saved, can edit a few different variables to customize how it works in accordance with what you want.

5. Do a #questreload and the new plugin should be ready for use

Here is an example script:


Code:

sub EVENT_SPAWN {
        quest::stoptimer("attack");
}
sub EVENT_COMBAT {
        if ($combat_state == 1) {
                quest::settimer("attack",10);
        }
        if ($combat_state == 0) {
                quest::stoptimer("attack");
        }
}

sub EVENT_TIMER {

        plugin::ArcheryAttack(1000, 10, 1);


}

Every 10 seconds, the example script will fire an arrow at the the main tank. This arrow will have a base damage in the range of 900-1100, which is then further modified by where the arrow will strike. The arrow will then check to see if it crits or misses, and doubles damage on a crit, or set to 0 if it misses. The damage is then applied to the player through an invisible message, and a custom message is sent to the player telling them where they were struck by the arrow, and for how much.

Usage for this Plugin? Can set up a mob to have three timers once aggroed, one for the Single Target, one for the Hit all, one for hit random target on a permarooted mob and you now have a ranged fight. Give the mob high min/max damage to encourage people to stay out of melee. Was more developed as a way to see if I could do something like this.

Current caveat, I could not find a way to pull a player's Shielding, so I used AC to simulate (poorly) a player's shielding. AC / 75 = Shielding Percent. If anyone has any ideas to get around that, please let me know!

trevius 02-24-2010 10:30 PM

That looks like a pretty fun plugin for custom servers wanting to simulate ranged attacks. I have actually been wanting to add one in that simulates it more like you might see on Live using the following commands and more:

Code:

CheckLoSToLoc(x, y, z, [mob_size])
ProjectileAnim(mob, item_id, [IsArrow?, speed, angle, tilt, arc])
DoSpecialAttackDamage()

Though, I may have to go even further and try to export some of the damage calculating functions from mob.cpp to perl so I can use the actual damage calculations for the NPC as if it was meleeing the client(s). I will have to look into it, but maybe some of these functions could be exported to allow for some cool flexibility:

Code:

bool Mob::CheckHitChance(Mob* other, SkillType skillinuse, int Hand)
bool Mob::AvoidDamage(Mob* other, sint32 &damage)
void Mob::MeleeMitigation(Mob *attacker, sint32 &damage, sint32 minhit)
bool NPC::Attack(Mob* other, int Hand, bool bRiposte)
sint32 Mob::ReduceDamage(sint32 damage)
sint32 Mob::ReduceMagicalDamage(sint32 damage)

I also think it would be nice to have an option for setting timers to allow it to set the timer in milliseconds instead of seconds. A simple optional bool at the end of the command should work just fine. You could then adjust timers to happen at any interval you could possibly want :)

Or, maybe I should just do it the right way and try to just write it all in the source code so Ranger class NPCs with Bows in their loot table or with a Bow weapon model equiped will use ranged attacks automatically (maybe with a rule option to enable). I think KLS has some ranged NPC code started already, so it might just mean finishing that code off. I think the hard part will be making it so they don't constantly run toward the character, as I think they should just get within a certain range and check LoS and shoot from that position until they are out of range or lose their LoS to the target.

nenelan 02-24-2010 11:02 PM

Hmm. Your option is much better. I'm still rather new to the whole perl scripting side of things, so it was a challenge I made myself to see if I could do something a bit more advanced than "give me this item".
That being said, I did get a nice encounter working with this plugin, however, I will be the first to admit, it has its share of redundancy in the code, it is somewhat sloppy, and could be streamlined.
I admit I am very thrilled with the prospect of ranger (or any bow using npcs) using a bow if they have one in their loot table/model equipped. That's something that even live hasn't done yet!

krujo81 12-27-2010 08:23 PM

kinda old i know but has anyone finshed anything 100%?. Because Necro swarm pet aa are supose to be archers yet they melee lol.

Ill take a look at this code and see if i cant use it but am rather new to this stuff myself

Randymarsh9 01-30-2011 09:03 PM

Yeah is this functional? I noticed there is a rule in the DB about npc archery damage now, but I haven't found a way to make them actually use bows.

Caryatis 01-30-2011 09:59 PM

Add special attack 'Y' to NPCs and they will use archery if their target is out of melee range. The rule is a multiplier of their normal dmg since we dont have values for ranged npc dmg in the db yet.


All times are GMT -4. The time now is 08:21 AM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.