EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Quests::Custom (https://www.eqemulator.org/forums/forumdisplay.php?f=671)
-   -   Very simple scalable array + hash based quest template (https://www.eqemulator.org/forums/showthread.php?t=29846)

Valdaun 10-23-2009 01:15 PM

Very simple scalable array + hash based quest template
 
I've been working on this quest for a few days now and I thought I would share the completed product. I really wanted to make a quest template with the following attributes:
  • Very easy to modify
  • Very easy to scale up to dozens+ of items
  • Heavy use of variables to eliminate redundancy, especially of item IDs
  • Say links + item links + direct whispering, because those rock!

I knew from previous programming experience that multi dimensional arrays (or I guess perl calls them hashes) holding all the relevant bits of information would be the way to go, but it took some playing to get the syntax and loops just right since I am really only fluent in PHP.

Anyway, below is my completed quest using this method. As this particular quest was intended to give my family and friends a way to start off with some decent equipment, I took some inspiration from current events ... hopefully no one finds the slight US political nod offensive; it's all in good fun! ;)

Lastly, please note that a previous version of this was causing Plane of Knowledge to crash on startup simply by existing in the poknowledge quest folder. I would have to remove it, let the zone start, then put it back and run #reloadqst to get things working. I have not yet reset my server since my final revision, but if anyone has any thoughts on why a quest .pl file would crash a zone bootup I would love to hear them! I am actually suspecting it might be more due to the NPC itself, so deleting him and starting over is on my list of things to try.

The Quest:
Code:

#
# Simple & Scalable
# Array + hash based quest template
#
# Valdaun  10/23/2009
#
################################################
# All turnins follow simple method:
#
# Quest Item + Component Cost = Reward
#
# Extremely scalable from a handful of sets
# to dozens, without any code bloat.
#
# All item IDs are typed only one time,
# reducing errors and simplifying changes
#
# Heavy use on say and item links + npc whispers
# for minimal say spam and ease of npc interaction
#
################################################
#
#######    BEGIN ARRAY MODS    #################
#
################################################
#
# QUEST TURNINS AND REWARDS
#
################################################
#
# Component costs for quest turnins
#
my $rare_cost = 22503;        # blue diamond (dropped)
my $mid_cost = 10031;        # fire opal (bought)

################################################
#
# Arrays containing the item to turnin as the array index,
# which points to a cost & reward hash which will be looped
# through later in the say and handin sections.
#
my %fabled_turnins = (
        5401 => { "cost" => $rare_cost, "reward" => 68259 },        #Mithril 2 hander & fabled
        5403 => { "cost" => $rare_cost, "reward" => 68260 },        #Ghoulbane & fabled
        5500 => { "cost" => $rare_cost, "reward" => 68263 },        #SS of Ykesha & fabled
        5412 => { "cost" => $rare_cost, "reward" => 68262 }        #Razing Sword of Skarlon & fabled
);

my %defiant_turnins = (
        8003 => { "cost" => $mid_cost, "reward" => 50550 },        #Longbow & Rough Defiant Bow
        9004 => { "cost" => $mid_cost, "reward" => 50551 },        #Kite Shield & Rough Def. Chitin Shield (tank)
        5006 => { "cost" => $mid_cost, "reward" => 50549 },        #Halberd & R.D. Halberd
        6006 => { "cost" => $mid_cost, "reward" => 50540 },        #Warhammer & R.D. Hammer
        8007 => { "cost" => $mid_cost, "reward" => 50546 },        #Shuriken & R.D. Knuckle Dusters
        5002 => { "cost" => $mid_cost, "reward" => 50543 },        #Long Sword & R.D. Longsword
        9002 => { "cost" => $mid_cost, "reward" => 50552 },        #Round Shield & R.D. Round Shield (priest)
        7002 => { "cost" => $mid_cost, "reward" => 50544 },        #Rapier & R.D. Stone Dagger (rog)
        7001 => { "cost" => $mid_cost, "reward" => 50545 },        #Dagger & R.D. Serrated Dagger (caster)
        5001 => { "cost" => $mid_cost, "reward" => 50542 },        #Short Sword & R.D. Short Sword
        6003 => { "cost" => $mid_cost, "reward" => 50541 },        #Mace & R.D. Scepter (priest)
        6012 => { "cost" => $mid_cost, "reward" => 50547 },        #Worn Great Staff & R.D. Spiked Staff (2hb)
        7003 => { "cost" => $mid_cost, "reward" => 50548 }        #Spear & R.D. Trident (2hp)
);

################################################
#
#  Whisper Color
#
my $whisper_color = 315;        # tan

################################################
#
#  Experience rewards
#
my $exp_big = 5000000;        # 1 yellow bar of AA
my $exp_mid = 50000;        # 1-4 worth of exp, slows down fast 6+

################################################
#
#######    END VARIABLE MODS    ###############
#
################################################

sub EVENT_SAY {

################################################
#
#  Conversation navigation links for say section
#
my $fabled = quest::saylink("fabled");
my $defiant = quest::saylink("defiant");
my $looking_for = quest::saylink("looking for");
my $trade_for = quest::saylink("trade for");

        if($text=~/hail/i)
        {
                quest::say("My friend $name, come talk to me for a minute.  My name is
                                  Barack O'Pally, and I represent a change you can believe in! 
                                Now listen to this, for too long have the rich and powerful in
                                this world held onto all of the [$fabled] and [$defiant] weapons
                                of yore.  I think this is a travesty and I intend to do something
                                about it.  Say it with me ... YES WE CAN!");
        }

        if($text=~/fabled/i)
        {
                $client->Message($whisper_color, "So this is what we are going to do.  You are going
                                to go out and collect some level 40-50 weapons and, and then I will
                                turn around and give you the fabled version just out of the kindness
                                of my heart, and my desire to change this world!  Would you like to
                                see what I am [$looking_for]?");
        }

        if($text=~/looking for/i)
        {
                $client->Message($whisper_color, "At this time, I am able to transmute the following
                                weapons into their fabled counterparts:");

                # loop through item => reward array and send a list of items to client
                foreach $id (sort keys %fabled_turnins)
                {
                        my $item_link = quest::varlink($id);
                        my $cost_link = quest::varlink($fabled_turnins{$id}{"cost"});
                        my $reward_link = quest::varlink($fabled_turnins{$id}{"reward"});

                        $client->Message($whisper_color, "$item_link + $cost_link turn into $reward_link")
                }
        }

        if($text=~/defiant/i)
        {
                $client->Message($whisper_color, "To help get your start in this world with a little
                                leg up from The Man, I can get you some Rough Defiant quality weapons
                                for a minimal cost.  Would you like to see what I can [$trade_for]?");
        }

        if($text=~/trade for/i)
        {
                $client->Message($whisper_color, "At this time, I am able to make the following trades. 
                                Most of these basic weapons are found on city merchants.");
               
                # loop through item => reward array and send a list of items to client
                foreach $id (sort keys %defiant_turnins)
                {
                        my $item_link = quest::varlink($id);
                        my $cost_link = quest::varlink($defiant_turnins{$id}{"cost"});
                        my $reward_link = quest::varlink($defiant_turnins{$id}{"reward"});

                        $client->Message($whisper_color, "$item_link + $cost_link for $reward_link")
                }
        }
}

sub EVENT_ITEM {

        # used to determine if anything needs handed back
        my $gaveitem = 0;

        # loop through item => reward array looking for a match
        foreach $item_id (sort keys %fabled_turnins)
        {
                $cost = $fabled_turnins{$item_id}{"cost"};
                $reward = $fabled_turnins{$item_id}{"reward"};

                # hand out the goods on a match of item + cost
                if (plugin::check_handin(\%itemcount, $item_id => 1, $cost => 1))
                {
                        $gaveitem = 1;

                        quest::emote(" uses the power of the people to grant you whats yours!");
                        quest::summonitem($reward);
                        quest::ding;

                        # this lets us grant a meaningful exp reward
                        # without giving a dozen+ levels worth at level 1
                        if ($ulevel > 39)
                        {
                                quest::exp($exp_big);
                        }

                        else
                        {
                                quest::exp($exp_mid);
                        }
                }
        }

        # loop through 2nd item => reward array looking for a match
        foreach $item_id (sort keys %defiant_turnins)
        {
                $cost = $defiant_turnins{$item_id}{"cost"};
                $reward = $defiant_turnins{$item_id}{"reward"};

                # hand out the goods on a match of item + cost
                if (plugin::check_handin(\%itemcount, $item_id => 1, $cost => 1))
                {
                        $gaveitem = 1;

                        quest::emote(" uses the power of the people to grant you whats yours!");
                        quest::summonitem($reward);
                        quest::exp(50000);
                        quest::ding;
                }
        }

        # if there were no matches, give back what was turned in
        if ($gaveitem == 0)
        {
                plugin::return_items(\%itemcount);
        }
}


trevius 10-23-2009 04:59 PM

Very nice and clean format. Thanks for sharing it :)

BTW, using quest::saylink outside of EVENT_SAY will almost always cause a zone crash, which may be why you were seeing your crashes. I am not really sure what causes the crash, but as long as you keep them inside EVENT_SAY, it isn't an issue.

Valdaun 10-23-2009 05:04 PM

Thank you! By the way, you are right about it being the quest::saylink variables outside of EVENT_SAY. I moved them in, no more crash. whew!

trevius 10-23-2009 05:56 PM

I hope you don't mind, but I took the liberty to edit your post to adjust the saylink location in the script. Should be ready for anyone else to use it as-is now :)


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

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