Go Back   EQEmulator Home > EQEmulator Forums > Quests > Quests::Custom

Quests::Custom Custom Quests here

Reply
 
Thread Tools Display Modes
  #1  
Old 01-27-2013, 10:04 AM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default random loot, the easy way

i finally got around to using the new global_npc.pl script
it makes loot randomization so much easier...

this small snippet
- doesn't make changes to default loot chances
- only gives npcs with existing loot tables are given an extra item
(so untargetable, invisible npcs won't turn into floating weapons)
- verifies itemid is valid via temporary itemlink creation

EQEmu\quests\templates\global_npc.pl
Code:
sub EVENT_SPAWN {
    return unless $npc->GetLoottableID();
    my ($tested, $itemid);
    do {
        $itemid = ( int rand 131474 ) + 1001;
        $tested = quest::varlink($itemid);
    } while $tested =~ /INVALID/;
    $npc->AddItem($itemid);
}
- can easily be expanded upon

examples:
filter specific items from roll
destroy extra item under certain conditions
roll for chance at extra item
additional random items

NOTE: you'll want to change the number from 131474 to whatever the highest itemid is in your items table and subtract 1001 (or your lowest itemid) from that number.
__________________
I muck about @ The Forge.
say(rand 99>49?'try '.('0x'.join '',map{unpack 'H*',chr rand 256}1..2):'incoherent nonsense')while our $Noport=1;
Reply With Quote
  #2  
Old 01-27-2013, 11:21 AM
Drajor's Avatar
Drajor
Developer
 
Join Date: Nov 2012
Location: Halas
Posts: 355
Default

Hah that is awesome!
__________________
Drajor regards you indifferently -- what would you like your tombstone to say?
Reply With Quote
  #3  
Old 01-27-2013, 12:01 PM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default

glad you like it. i've added all sorts of bells and whistles to this on my test server. trivial encounter check, filtering based on item usability by encounter participants and/or an arbitrary never-drop list, minimum base chance and additional chance scaled by npc level, etc.

my previous method required that you modify every existing npc quest script you wanted to apply random loot to. needless to say, the recent addition of global_npc simplified things a great deal. thanks, akkadius!
__________________
I muck about @ The Forge.
say(rand 99>49?'try '.('0x'.join '',map{unpack 'H*',chr rand 256}1..2):'incoherent nonsense')while our $Noport=1;
Reply With Quote
  #4  
Old 01-28-2013, 06:44 PM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default intentional complications

using something very close to this to verify that the npc can equip the item in question before the call to $npc->AddItem(). read: no more augfists, yay!

it can be modified for use as an additional validation step while picking the random item (filtering out items that are not usable by an participant in the encounter, for example).

this was fun! (no sarcasm)

Code:
use 5.012;
no strict 'vars';

use constant {
    MIN_ITEMID    => 1001,
    MAX_ITEMID    => 132475,
};

# class patterns used to build regular expressions for bit values
my $war = '1|war(?:rior)?';
my $clr = '2|cl(?:eric|r)';
my $pal = '3|pal(?:adin)';
my $rng = '4|r(?:anger|ng)';
my $shd = '5|sh(?:adowknight|d)';
my $dru = '6|dru(?:id)?';
my $mnk = '7|m(?:o)?nk';
my $brd = '8|b(?:a)?rd';
my $rog = '9|rog(?:ue)?';
my $shm = '10|sh(?:aman|m)';
my $nec = '11|nec(?:romancer)?';
my $wiz = '12|wiz(?:ard)?';
my $mag = '13|mag(?:ician)?';
my $enc = '14|enc(?:hanter)?';
my $bst = '15|b(?:eastlord|st)';
my $ber = '16|ber(?:serker)?';

# race patterns used to build regular expressions for bit values
my $hum = '1|hum(?:an)?';
my $bar = '2|bar(?:barian)?';
my $eru = '3|eru(?:dite)?';
my $elf = '4|(?:wood )?elf';
my $hie = '5|hi(?:gh elf|e)';
my $def = '6|d(?:ark elf|ef)';
my $hel = '7|h(?:alf-elf|el)';
my $dwf = '8|dw(?:ar)?f';
my $trl = '9|tr(?:ol)?l';
my $ogr = '10|ogr(?:e)?';
my $hlf = '11|h(?:alfling|lf)';
my $gnm = '12|gn(?:ome|m)';
my $iks = '128|iks(?:ar)?';
my $vah = '130|vah(?: shir)?';
my $frg = '330|fr(?:oglok|g)';
my $drk = '522|dr(?:akkin|k)';

# get bit value for any playable race/class you pass it
# works with numeric values, abbreviations, and full spellings 
sub GetBitFor {
    my $bit = {
        1     => qr/^$war|$hum$/i,
        2     => qr/^$clr|$bar$/i,
        4     => qr/^$pal|$eru$/i,
        8     => qr/^$rng|$elf$/i,
        16    => qr/^$shd|$hie$/i,
        32    => qr/^$dru|$def$/i,
        64    => qr/^$mnk|$hel$/i,
        128   => qr/^$brd|$dwf$/i,
        256   => qr/^$rog|$trl$/i,
        512   => qr/^$shm|$ogr$/i,
        1024  => qr/^$nec|$hlf$/i,
        2048  => qr/^$wiz|$gnm$/i,
        4096  => qr/^$mag|$iks$/i,
        8192  => qr/^$enc|$vah$/i,
        16384 => qr/^$bst|$frg$/i,
        32768 => qr/^$ber|$drk$/i,
    };
    my $for = shift;
    while ( my ( $key, $val ) = each %$bit ) {
        return $key if $for ~~ $val;
    }
    return 0;
}

sub CanEquip {

    # itemid to check
    my $itemid = shift;

    # coderef for $npc->GetItemStat()
    my $GISref = sub { $npc->GetItemStat(@_) };

    # list of tests we want to do, in order of importance
    # 1. is itemid within valid range?
    # 2. is itemid tied to a valid item (some id number gaps exist)?
    # 3. is itemid able to be equipped at all?
    # 4. is itemid not an aug?
    # 5. is itemid not deity specific?
    # 6. is itemid's required level less than or equal to my level?
    # 7. is itemid's class restriction compatible with my class?
    # 8. is itemid's race restriction compatible with my class?
    my $test = [
        sub { shift ~~ [ MIN_ITEMID .. MAX_ITEMID ] },
        sub { quest::varlink(shift) !~ /INVALID/ },
        sub { $GISref->( shift, "slots" ) },
        sub { !$GISref->( shift, "augtype" ) },
        sub { !$GISref->( shift, "deity" ) },
        sub { $GISref->( shift, "reqlevel" ) <= $mlevel },
        sub { $GISref->( shift, "classes" ) & GetBitFor( $npc->GetClass() ) },
        sub { $GISref->( shift, "races" ) & GetBitFor( $npc->GetRace() ) },
    ];

    # run through tests, stopping at first failure
    foreach (@$test) {
        return 0 unless $_->($itemid);
    }

    # passed all tests
    return 1;
}
__________________
I muck about @ The Forge.
say(rand 99>49?'try '.('0x'.join '',map{unpack 'H*',chr rand 256}1..2):'incoherent nonsense')while our $Noport=1;

Last edited by c0ncrete; 01-28-2013 at 06:45 PM.. Reason: grammatical failure
Reply With Quote
  #5  
Old 01-29-2013, 04:21 PM
jdoran
Hill Giant
 
Join Date: Jul 2012
Posts: 212
Default

I've never played on such a server, so I wonder why one would ever fight tough mobs when there are rats in the newbie area potentially dropping end-game gear. (I'm not saying that is necessarily a bad thing, I just wonder how things would play out)
Reply With Quote
  #6  
Old 01-29-2013, 05:39 PM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default

some people just like the idea of random loot. the initial snippet was to give those people something to play with. technically speaking, most servers don't actually employ randomization, they simply scramble the drops in the database. they're still static that way. the misnomer is a pet peeve of mine.

as for your concerns, i had them as well. i'm working on implementing ways to determine if the encounter was trivial and remove the extra item. i'm also looking into filtering out loot based on the required level of the item. so the npc won't get something outside of its level range.

my objective on my personal server is for there to only be a very small chance of the extra item, which scales up a tiny bit with npc difficulty (starting at level 11), so the extra item won't be something that is a common occurrence to begin with.

finally, i'm considering giving the npcs in these rare instances abnormal abilities, so as to make things more of a challenge, given the extra bounty.

the devil is in the details ...
__________________
I muck about @ The Forge.
say(rand 99>49?'try '.('0x'.join '',map{unpack 'H*',chr rand 256}1..2):'incoherent nonsense')while our $Noport=1;
Reply With Quote
  #7  
Old 01-29-2013, 07:53 PM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default

yow. the original won't work as posted because of the way quest::varlink() works. if you call it without a client as the initiator, the zone will crash. i was testing the functionality via EVENT_SAY, so it worked without issue.

compiling a minor source modification to see if it takes care of the crash without altering the functionality of quest::varlink() now. it'll just return an empty string if there is no client initiator, but only after it validates the itemid passed to it.
__________________
I muck about @ The Forge.
say(rand 99>49?'try '.('0x'.join '',map{unpack 'H*',chr rand 256}1..2):'incoherent nonsense')while our $Noport=1;
Reply With Quote
  #8  
Old 01-29-2013, 09:24 PM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default

applying the source change found here and changing

Code:
while $tested =~ /INVALID/
to

Code:
while $tested =~ /INVALID ITEM/
resolved the issue.
__________________
I muck about @ The Forge.
say(rand 99>49?'try '.('0x'.join '',map{unpack 'H*',chr rand 256}1..2):'incoherent nonsense')while our $Noport=1;
Reply With Quote
  #9  
Old 01-30-2013, 12:48 PM
jdoran
Hill Giant
 
Join Date: Jul 2012
Posts: 212
Default

I can see the attraction of an occasional random item (random rewards are more effective psychologically, think Pavlov did some work on this). I'd actually like to play on such a server to check it out.

If I were doing such a thing, I would create a singleton on the server that built a list of items by level. Then have it select something from a requested range through a new Perl call. (I know you weren't asking for suggestions, but I thought I'd throw that out there. It might inspire someone).

Edit: I just realized that this would be a good candidate for the shared memory region. No need to replicate the table across zones.
Reply With Quote
  #10  
Old 01-30-2013, 01:04 PM
c0ncrete's Avatar
c0ncrete
Dragon
 
Join Date: Dec 2009
Posts: 719
Default

no worries. suggestions are always appreciated. i've got plenty of ideas, just not enough skill to do anything other than hack them together with perl and my limited knowledge of c++.
__________________
I muck about @ The Forge.
say(rand 99>49?'try '.('0x'.join '',map{unpack 'H*',chr rand 256}1..2):'incoherent nonsense')while our $Noport=1;
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 07:58 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3