summaryrefslogtreecommitdiff
path: root/npc/items
diff options
context:
space:
mode:
authorJesusaves <cpntb1@ymail.com>2021-04-09 11:00:49 -0300
committerJesusaves <cpntb1@ymail.com>2021-04-09 11:00:49 -0300
commit8a4bf716002a017de77fe7df301ef8e4aaf00a2e (patch)
tree4947d0b015baad639fa07133369e9a09c8a468bc /npc/items
downloadserverdata-8a4bf716002a017de77fe7df301ef8e4aaf00a2e.tar.gz
serverdata-8a4bf716002a017de77fe7df301ef8e4aaf00a2e.tar.bz2
serverdata-8a4bf716002a017de77fe7df301ef8e4aaf00a2e.tar.xz
serverdata-8a4bf716002a017de77fe7df301ef8e4aaf00a2e.zip
Initial commit
Diffstat (limited to 'npc/items')
-rw-r--r--npc/items/cookie.txt22
-rw-r--r--npc/items/croconut.txt72
-rw-r--r--npc/items/gift.txt35
-rw-r--r--npc/items/master_skillbook.txt164
-rw-r--r--npc/items/music_toys.txt18
-rw-r--r--npc/items/rand_sc_heal.txt85
-rw-r--r--npc/items/recipes.txt352
-rw-r--r--npc/items/shovel.txt361
8 files changed, 1109 insertions, 0 deletions
diff --git a/npc/items/cookie.txt b/npc/items/cookie.txt
new file mode 100644
index 00000000..e451e844
--- /dev/null
+++ b/npc/items/cookie.txt
@@ -0,0 +1,22 @@
+// Evol script.
+// Author:
+// Jesusalva
+// Reid (?)
+// Description:
+// Prevents cookie from being used for too long
+
+function script UnequipCookie {
+ if (getequipid(EQI_HEAD_MID) == DeliciousCookie)
+ unequip(EQI_HEAD_MID);
+ return;
+}
+
+- script #DeliciousCookie NPC_HIDDEN,{
+ end;
+
+OnUnequip:
+ UnequipCookie();
+ end;
+
+}
+
diff --git a/npc/items/croconut.txt b/npc/items/croconut.txt
new file mode 100644
index 00000000..8e54971d
--- /dev/null
+++ b/npc/items/croconut.txt
@@ -0,0 +1,72 @@
+// Evol scripts.
+// Authors:
+// 4144
+// Reid
+// Description:
+// Allows to cut a Croconut in multiple parts.
+//
+// Possible choices for L_Weapon:
+// rif(countitem(35xx), l(getitemname(xx))), L_Weak,
+// rif(countitem(35yy), l(getitemname(yy))), L_Good,
+
+000-2-1,0,0,0 script Croconut NPC_HIDDEN,{
+ close;
+
+OnUse:
+ mesn "Narrator";
+ mesc(l("Do you want to cut this @@?", getitemlink(Croconut)), 9);
+ next;
+
+ menu
+ l("Yes."), L_Weapon,
+ l("No."), -;
+
+ getitem Croconut, 1;
+ close;
+
+L_Weapon:
+ mes "";
+ mesn "Narrator";
+ mesc(l("Which of your weapons do you want to use in order to cut this @@?", getitemlink(Croconut)), 9);
+ next;
+
+ menu
+ rif(countitem(Knife) > 0, l(getitemname(Knife))), L_Weak,
+ rif(countitem(PiouSlayer) > 0, l(getitemname(PiouSlayer))), L_Weak,
+ rif(countitem(TrainingGladius) > 0, l(getitemname(TrainingGladius))), L_Good,
+ rif(countitem(WoodenSword) > 0, l(getitemname(WoodenSword))), L_Weak,
+ rif(countitem(ArtisBacksword) > 0, l(getitemname(ArtisBacksword))), L_Good,
+ l("Bare Hands"), -;
+
+L_TooWeak:
+ mes "";
+ mesn "Narrator";
+
+ .@q = rand(5);
+ if (.@q == 0) goto L_TooWeakLost;
+ if ( (.@q == 1) || (.@q == 2) ) goto L_TooWeakFail;
+ if ( (.@q == 3) || (.@q == 4) || (.@q == 5) ) goto L_Weak;
+
+L_TooWeakLost:
+ mesc(l("You hit too hard with your fist, you destroyed your @@.", getitemlink(Croconut)), 9);
+
+ close;
+
+L_TooWeakFail:
+ mesc(l("Your hands are too weak, you did not succeed in opening this @@.", getitemlink(Croconut)), 9);
+
+ getitem Croconut, 1;
+ close;
+
+L_Weak:
+ mesc(l("You opened the @@ in two parts, but you crushed one of them.", getitemlink(Croconut)), 9);
+
+ getitem HalfCroconut, 1;
+ close;
+
+L_Good:
+ mesc(l("You perfectly cut your @@ into two edible parts.", getitemlink(Croconut)), 9);
+
+ getitem HalfCroconut, 2;
+ close;
+}
diff --git a/npc/items/gift.txt b/npc/items/gift.txt
new file mode 100644
index 00000000..be77bdfa
--- /dev/null
+++ b/npc/items/gift.txt
@@ -0,0 +1,35 @@
+// Referral Gifts
+// Rebased from Moubootaur Legends
+// Author:
+// Jesusalva
+
+function script OpenFriendGift {
+ if (BaseLevel < 5) {
+ dispbottom(l("You must reach level 5 to open this gift."));
+ getitembound(FriendGift, 1, 1);
+ return;
+ }
+
+ getitem(Acorn, 1); // FIXME: placeholder
+ //getitem(EventCoin, rand(1,3));
+
+ .@refVault = bitwise_get(getvaultvar(REFERRAL_PROG), 0x00FFFFFF, 0);
+ .@refChar = "playerCache"::vault2char(.@refVault);
+ .@refName$ = "playerCache"::char2name(.@refChar);
+
+ //$REFERRAL_IDS[.@refVault] += 1;
+ // ^ this doesn't seem to serve any purpose...
+ // if we want to keep track of how many accounts someone referred it
+ // should be something like:
+ // .@count = getvaultvar(REFERRAL_COUNT, .@refVault);
+ // setvaultvar(REFERRAL_COUNT, .@count + 1, .@refVault);
+
+ dispbottom(l("Oooh, a gift from %s!", .@refName$));
+ rodex_sendmail(.@refChar, "TMW Team",
+ "Invite Accepted",
+ sprintf("%s accepted your invitation and reached level 5!\n"
+ "As they get stronger, more rewards will be sent to you!",
+ strcharinfo(PC_NAME)),
+ rand(50, 150));
+ return;
+}
diff --git a/npc/items/master_skillbook.txt b/npc/items/master_skillbook.txt
new file mode 100644
index 00000000..007125cc
--- /dev/null
+++ b/npc/items/master_skillbook.txt
@@ -0,0 +1,164 @@
+// The Mana World script.
+// Author:
+// Jesusalva
+// Elvano
+// Description:
+// Contains master skills which can only be learnt after killing boss
+// See also: https://forums.themanaworld.org/viewtopic.php?f=2&t=19918
+// Notes:
+// Not exactly as Elvano proposal. I actually care for restrictions you know...
+// Variables:
+// PERMANENT:
+// MASTERBOOK_PAGES - How many pages your Master Book have.
+// Defaults to zero, so you can't @item it.
+// MASTERBOOK_SKILL - An array with the skills you have learnt from Master Book.
+// - It's more flexible this way.
+// TEMPORARY:
+// @mb_BossId - Contains the MobID of the boss your party killed.
+// @mb_SkillId - Contains the SkillID which can be learnt with the boss.
+// @mb_ItemId - Contains the Feather Id to write (or whatever)
+// @mb_ItemAm - How many ink is required to write the skill
+// Remember: @mb_BossId will be reset to zero after 15 seconds from boss death.
+// Or upon logout. Or when changing maps. Temporary variables aren't reliable.
+//
+// @mb_BossId controls if you'll try to LEARN a skill, or READ the book.
+// Remember: A dialog prevents timer events from happening, but doesn't stops the timer.
+// TODO: Currently no way to get skill name from database (add getskillinfo() to server-plugin please)
+// TODO: Reset @mb_* when register_skill() finish
+// TODO: You cannot get Magic Feather anywhere in the game (yet)
+// TODO: See if the time (15s) is enough.
+// TODO: Skill level up
+// TODO: Use the data supplied by magic.txt
+
+- script #MasterBook NPC_HIDDEN,{
+
+
+ function register_skill {
+
+ setnpcdialogtitle l(.book_name$);
+
+ // If boss is set, but is negative, this means somebody else defeated it
+ if (@mb_BossId < 0)
+ {
+ mesc l("You did not defeat the boss, you can't learn any skills.");
+ @mb_BossId=0;
+ close;
+ }
+
+ // Report the boss you killed, and the boss level
+ .@mb_lvl=strmobinfo(3, @mb_BossId);
+ mesc l("You just defeated the following boss: @@ (Lv. @@)", strmobinfo(1, @mb_BossId), .@mb_lvl);
+
+ // The boss must have a skill
+ if (!@mb_SkillId)
+ {
+ mesc l("But there is no skill to be learnt from this boss.");
+ @mb_BossId=0;
+ close;
+ }
+ // You must have free pages
+ if (array_entries(MASTERBOOK_SKILL) >= MASTERBOOK_PAGES)
+ {
+ mesc l("But you ran out of empty pages on this book.");
+ @mb_BossId=0;
+ close;
+ }
+ // TODO: Party Level Range
+ // You must be at most 30 levels below the monster level
+ if (BaseLevel+30 < .@mb_lvl)
+ {
+ mesc l("But you are out of the boss level range.");
+ @mb_BossId=0;
+ close;
+ }
+ // You must have enough materials
+ if (countitem(@mb_ItemId) < @mb_ItemAm)
+ {
+ mesc l("But you do not have enough Magic Ink. (You need: @@ @@)", @mb_ItemAm, getitemlink(@mb_ItemId));
+ //@mb_BossId=0;
+ close;
+ }
+
+ // Allow you to check which skills are here to learn
+ mes "";
+ mesc l("You have: @@/@@ @@", countitem(@mb_ItemId), @mb_ItemAm, getitemlink(@mb_ItemId));
+ mesc l("Skill Available: %s", getskillname(@mb_SkillId));
+ select
+ rif(!getskilllv(@mb_SkillId), l("Learn Skill")),
+ l("Do not learn");
+ mes "";
+ if (@menu == 1)
+ {
+ delitem @mb_ItemId, @mb_ItemAm;
+ skill(@mb_SkillId, 1, 0);
+ array_push(MASTERBOOK_SKILL, @mb_SkillId);
+ closeclientdialog;
+ dispbottom l("You have learnt the skill.");
+ }
+ @mb_BossId=0;
+ close;
+ }
+
+
+ function read_book {
+
+ setnpcdialogtitle l(.book_name$);
+ mesc l("@@/@@ pages used.", array_entries(MASTERBOOK_SKILL), MASTERBOOK_PAGES);
+
+ mesc l("List of known master skills:");
+ mes "";
+ for (.@i = 0; .@i < getarraysize(MASTERBOOK_SKILL); ++.@i) {
+ mesc l("* Skill ID: @@", MASTERBOOK_SKILL[.@i]);
+ }
+ close;
+ }
+
+OnUse:
+ // We assume if @mb_BossId is set, everything else is set, too
+ if (@mb_BossId)
+ register_skill;
+ if (openbook())
+ read_book;
+ closeclientdialog();
+ close;
+
+OnInit:
+ .book_name$ = getitemname(MasterBook);
+ .distance = 1;
+ end;
+
+OnUnset:
+ @mb_BossId=0;
+ @mb_SkillId=0;
+ @mb_ItemId=0;
+ @mb_ItemAm=0;
+ end;
+}
+
+// Script Helper
+// BossSlain(npcname, "variable")
+function script BossSlain {
+ .@n$=getarg(0);
+ // Error
+ if (!playerattached())
+ return;
+ // Only the party which defeated the boss can learn the skill
+ getmapxy(.@m$, .@x, .@y, 0);
+ .@party=getcharid(1);
+ if (.@party > 0)
+ {
+ setd(getarg(1), .@party);
+ areatimer(.@m$, .@x-15, .@y-15, .@x+15, .@y+15, 10, .@n$+"::OnBossCheck");
+ mapannounce .@m$, "Boss deafeated by Party: " + getpartyname(.@party), bc_all;
+ }
+ else
+ {
+ setd(getarg(1), -2);
+ areatimer(.@m$, .@x-15, .@y-15, .@x+15, .@y+15, 10, .@n$+"::OnBossCheck");
+ addtimer(20, .@n$+"::OnBegin");
+ mapannounce .@m$, "Boss deafeated by: " + strcharinfo(0), bc_all;
+ }
+ return;
+}
+
+
diff --git a/npc/items/music_toys.txt b/npc/items/music_toys.txt
new file mode 100644
index 00000000..8583f65e
--- /dev/null
+++ b/npc/items/music_toys.txt
@@ -0,0 +1,18 @@
+// Evol scripts.
+// Authors:
+// Quillia
+// mekolat (legacy delay logic)
+// Description:
+// Allows the RubberBat to be squeezed.
+//
+
+- script RubberBat NPC_HIDDEN,{
+ close;
+
+OnUse:
+ if (gettimetick(2) - @lastbat < 2) close;
+ specialeffect(70, AREA, playerattached()); // effect 70 defined in client-data/effects.xml
+ @lastbat = gettimetick(2);
+
+ close;
+}
diff --git a/npc/items/rand_sc_heal.txt b/npc/items/rand_sc_heal.txt
new file mode 100644
index 00000000..e4b0875a
--- /dev/null
+++ b/npc/items/rand_sc_heal.txt
@@ -0,0 +1,85 @@
+// Evol scripts.
+// Author:
+// Reid
+// Description:
+// Random heal every x seconds.
+//
+// Variables:
+// @delay Second of healing
+// @min Min amount of healing
+// @max Max amount of healing
+// @type 1 Heal
+// 2 Other
+// 3 Special 1
+// 4 Special 2
+
+- script rand_sc_heal -1,{
+
+ // Add remaning bonus if the last one hasn't finished
+ function remaining_bonus
+ {
+ if (getstatus(getarg(0)))
+ {
+ .@old_val1 = getstatus(getarg(0), 1);
+ .@old_delay = getstatus(getarg(0), 4) * 1000;
+
+ // change the delay to prevent fast healing
+ if (.@old_delay > @delay)
+ {
+ @delay = .@old_delay;
+ @val1 += .@old_val1;
+ }
+ else
+ {
+ @val1 += (.@old_val1 * .@old_delay) / @delay;
+ }
+ }
+ else
+ {
+ @val1 = @val3;
+ }
+ return;
+ }
+
+OnUse:
+ if (@delay <= 0) close;
+
+ // minimum between @min and bVit / 2 * BaseLevel / 10
+ .@vitality_bonus = min(@min, readparam(bVit) * BaseLevel / 20);
+ .@rand_heal_val = rand(@min, @max);
+
+ // val1 is the heal value without the vitality bonus
+ @val1 = .@rand_heal_val / @delay;
+ @val3 = (.@rand_heal_val + .@vitality_bonus) / @delay;
+
+ if (@val1 <= 0) close;
+
+ @delay *= 1000; // Put the delay in ms
+
+ switch (@type)
+ {
+ case 1:
+ .@skill = SC_S_LIFEPOTION;
+ break;
+ case 2:
+ .@skill = SC_L_LIFEPOTION;
+ break;
+ case 3:
+ .@skill = SC_G_LIFEPOTION;
+ break;
+ case 4:
+ .@skill = SC_M_LIFEPOTION;
+ break;
+ default :
+ .@skill = 0;
+ break;
+ }
+ if (.@skill != 0)
+ {
+ remaining_bonus(.@skill);
+ sc_end .@skill;
+ sc_start2 .@skill, @delay, @val1, 1;
+ }
+
+ close;
+}
diff --git a/npc/items/recipes.txt b/npc/items/recipes.txt
new file mode 100644
index 00000000..42cdf51b
--- /dev/null
+++ b/npc/items/recipes.txt
@@ -0,0 +1,352 @@
+// Evol script.
+// Author:
+// Jesusalva
+// Micksha
+// Description:
+// Contains recipe books for Evol Online
+
+// showRecipe( recipe{, recipe...} )
+function script showRecipe {
+ freeloop(true);
+ for (.@a = 0; .@a < getargcount(); ++.@a) {
+ .@const$ = data_to_string(getarg(.@a));
+
+ if (startswith(.@const$, "Craft")) {
+ // infer the item constant from the craft constant
+ .@recipe = getarg(.@a);
+
+ .@item = string_to_data(substr(.@const$, 5, getstrlen(.@const$) - 1));
+ } else {
+ // infer the craft constant from the item constant
+ .@recipe = string_to_data(sprintf("Craft%s", .@const$));
+ .@item = getarg(.@a);
+ }
+
+ if (.@item <= 0) {
+ // target item not found
+ continue;
+ }
+
+ if (!RECIPES[.@recipe] && !debug) {
+ // does not have the recipe
+ continue;
+ }
+
+ for (.@inv = 0; .@inv < 9; ++.@inv) {
+ .@size = getcraftrecipe(.@recipe, .@inv, .@qty[0], .@item_id[0]);
+
+ if (.@size < 0) {
+ if (.@size == -1) {
+ // recipe does not exist
+ break;
+ }
+ // inventory does not exist
+ break;
+ }
+
+ mes(l(".:: %s Recipe ::.", getitemlink(.@item)));
+
+ for (.@it = 0; .@it < .@size; ++.@it) {
+ .@recipe_item = .@item_id[.@it];
+ .@recipe_qty = .@qty[.@it];
+
+ if (.@recipe_item <= 0) {
+ break;
+ }
+
+ mesc(sprintf("%d/%d %s", countitem(.@recipe_item), .@recipe_qty, getitemlink(.@recipe_item)));
+ }
+
+ mes("");
+ .@count++;
+ }
+ }
+ freeloop(false);
+
+ return .@count > 0;
+}
+
+- script #RecipeBook NPC_HIDDEN,{
+ function read_book;
+ function read_cooking;
+ function read_smithery;
+ function read_tailoring;
+ end;
+
+function read_book {
+ setnpcdialogtitle l(.book_name$);
+ mesc l("This book has several bookmarks. Which one will you open?");
+ next;
+ menuint
+ l("Cooking"), CRAFT_COOKING,
+ l("Alchemy"), CRAFT_ALCHEMY,
+ l("Smithery"), CRAFT_SMITHERY,
+ l("Tailoring"), CRAFT_TAILORING,
+ l("Jewelery"), CRAFT_JEWELERY;
+ mes "";
+ switch (@menuret) {
+ case CRAFT_COOKING:
+ read_cooking(); break;
+ case CRAFT_SMITHERY:
+ read_smithery(); break;
+ case CRAFT_TAILORING:
+ read_tailoring(); break;
+ default:
+ mesc l("Unfortunately, there is nothing on this bookmark.");
+ mesc l("Perhaps, in future, someone adds it to this world.");
+ break;
+ }
+ close2();
+ return;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+function read_cooking {
+
+ setnpcdialogtitle l("Cooking Recipes");
+
+ mesc l("Eating is a necessity, but cooking is an art.");
+ mesc l("(All items must be placed exactly in this order for cooking work.)");
+ next;
+ mesc l("List of known cooking recipes:");
+ mes "";
+ mes ".:: " + l("Sandwiches") + " ::.";
+ mes "";
+
+ showRecipe(CarpSandwich,
+ PioulegSandwich,
+ MananaSandwich);
+
+ mes "";
+ mes ".:: " + l("Stew") + " ::.";
+ mes "";
+
+ showRecipe(SailorStew,
+ SquirrelStew,
+ MoubooStew);
+
+ mes "";
+ mes ".:: " + l("Plates") + " ::.";
+ mes "";
+
+ showRecipe(SeafoodPlate,
+ BarbecuePlate,
+ VeggiePlate);
+
+ mes "";
+ mes ".:: " + l("Desserts") + " ::.";
+ mes "";
+
+ showRecipe(Donut,
+ BlueberryCake,
+ CarrotCake);
+ return;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+function read_smithery {
+
+ setnpcdialogtitle l("Smithery Recipes");
+
+ mesc l("You will trust your life to this, so you better do a good job!");
+ mesc l("(All items must be placed exactly in this order.)");
+ next;
+ mesc l("List of known smithery recipes:");
+
+ mes();
+ mesf(".:: %s ::.", l("Chest Armor"));
+ mes();
+
+ showRecipe(LegionTrainingShirt,
+ LegionCopperArmor,
+ Chainmail,
+ Snakeplate,
+ LightPlatemail,
+ JustifierChest,
+ LegionIronArmor,
+ WarlordPlate,
+ TerraniteArmor,
+ AssassinChest,
+ BlackArmor,
+ GoldenWarlordPlate);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Leg Armor"));
+ mes();
+
+ showRecipe(ChainmailSkirt,
+ TerranitePants,
+ AssassinPants);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Gloves"));
+ mes();
+
+ showRecipe(CopperArmbands,
+ BromenalGloves,
+ IronArmbands);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Boots"));
+ mes();
+
+ showRecipe(BromenalBoots,
+ WarlordBoots);
+
+ return;
+}
+
+function read_tailoring {
+ setnpcdialogtitle(l("Tailoring Recipes"));
+
+ mesc(l("(All items must be placed exactly in this order.)"));
+ next();
+ mesc(l("List of known tailoring recipes:"));
+
+ mes();
+ mesf(".:: %s ::.", l("Chest Armor"));
+ mes();
+
+ showRecipe(CreasedShirt,
+ ArtisTankTop,
+ VneckJumper,
+ SailorShirt,
+ FineDress,
+ SilkRobe,
+ ForestArmor,
+ ApprenticeRobe,
+ PeltJacket,
+ SorcererRobe,
+ WizardRobe,
+ EvocatorRobe);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Leg Armor"));
+ mes();
+
+ showRecipe(CreasedShorts,
+ CottonSkirt,
+ PirateShorts,
+ SilkPants,
+ BrownTrousers,
+ BanditTrousers,
+ JeansChaps,
+ LeatherTrousers);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Gloves"));
+ mes();
+
+ showRecipe(ShortGloves,
+ Armbands,
+ CottonGloves,
+ BanditGloves,
+ SilkGloves,
+ LeatherGloves,
+ AssassinGloves);
+
+ next();
+ mes();
+ mesf(".:: %s ::.", l("Boots"));
+ mes();
+
+ showRecipe(LousyMoccasins,
+ Slippers,
+ CottonBoots,
+ BanditBoots,
+ ManaSlippers,
+ SquirrelBoots,
+ LeatherBoots,
+ RidingBoots,
+ AssassinBoots);
+
+ return;
+}
+
+
+OnUse:
+ if (openbook())
+ read_book();
+ closeclientdialog();
+ close;
+
+OnInit:
+ .book_name$ = getitemname(RecipeBook);
+ .distance = 1;
+ end;
+}
+
+//////////////////////////////////////////////////////
+// Below this line are utils for Gacha. We use callfunc() on itemDB.
+// Types: see constants.db - everything is a bitwise here
+// Rarity: 1 - basic, 2 - intermediary, 4 - advanced, 8 - expert, 16 - master
+// Rarity: 1 - training, 2 - basic, 4 - advanced, 8 - expert, 16 - legendary
+// Keep in mind! Expert and Master blueprints must be restricted!
+// MakeBlueprint(type, rarity)
+function script MakeBlueprint {
+ .@type=getarg(0, -1);
+ .@rarity=getarg(1, 1);
+
+ if (.@type & CRAFT_COOKING) {
+
+ // ----------------------------------
+ if (.@rarity & CRAFT_BASIC) {
+ }
+ if (.@rarity & CRAFT_INTERMEDIARY) {
+ }
+ if (.@rarity & CRAFT_ADVANCED) {
+ }
+ if (.@rarity & CRAFT_EXPERT) {
+ }
+ if (.@rarity & CRAFT_MASTER) {
+ }
+ // ----------------------------------
+
+ }
+ else if (.@type & CRAFT_SMITHERY)
+ {
+
+ // ----------------------------------
+ if (.@rarity & CRAFT_BASIC) {
+ }
+ if (.@rarity & CRAFT_INTERMEDIARY) {
+ array_push(.@recipes, CraftInfantryHelmet);
+ }
+ if (.@rarity & CRAFT_ADVANCED) {
+ }
+ if (.@rarity & CRAFT_EXPERT) {
+ }
+ if (.@rarity & CRAFT_MASTER) {
+ }
+ // ----------------------------------
+
+ }
+
+ // We don't have a .@recipes array D:
+ if (array_entries(.@recipes) <= 0) {
+ dispbottom l("This blueprint was blank.");
+ return;
+ }
+
+ // Select a recipe randomly
+ .@rcp=any_of(.@recipes);
+
+ // Double precision failsafe
+ if (RECIPES[.@rcp])
+ .@rcp=any_of(.@recipes);
+
+ // Learn the recipe or lose the item (and gain some EXP)
+ if (RECIPES_[.@rcp]) {
+ dispbottom l("It was a recipe you already knew...");
+ getexp (BaseLevel+JobLevel)*rand2(1,.@rarity), JobLevel+rand2(1,.@rarity);
+ } else {
+ dispbottom l("Learned a new recipe!");
+ RECIPES[.@rcp]=true;
+ }
+ return;
+}
diff --git a/npc/items/shovel.txt b/npc/items/shovel.txt
new file mode 100644
index 00000000..b4a5a968
--- /dev/null
+++ b/npc/items/shovel.txt
@@ -0,0 +1,361 @@
+// Evol scripts.
+// Author:
+// Travolta
+// Jesusalva
+// Description:
+// NPC to use shovel (dig, bury etc)
+
+- script Shovel -1,{
+
+ function CheckDigLocation {
+ getmapxy(.@map$, .@x, .@y, 0);
+
+ if (.@map$ != "001-1") {
+ if (getunits(BL_NPC, .@units, 1, .@map$, .@x - 1, .@y, .@x + 1, .@y + 1))
+ {
+ dispbottom(l("You cannot bury under a NPC!"));
+ return false;
+ }
+ }
+
+ // TODO: we should have a way to check for GROUNDTOP collisions too
+
+ for (.@i = 0; .@i < getarraysize(.WorldDigRect_Map$); .@i++)
+ {
+ if (!strcmp(.WorldDigRect_Map$[.@i], .@map$) &&
+ .WorldDigRect_x1[.@i] <= .@x &&
+ .WorldDigRect_x2[.@i] >= .@x &&
+ .WorldDigRect_y1[.@i] <= .@y &&
+ .WorldDigRect_y2[.@i] >= .@y)
+ {
+ return true;
+ }
+ }
+
+ dispbottom(l("You can't use the shovel here."));
+ return false;
+ }
+
+ function AddDigRect {
+ if (getargcount() < 5)
+ {
+ consolemes(CONSOLEMES_ERROR, "usage: AddDigRect(map$,x1,y1,x2,y2)");
+ return 0;
+ }
+ .@map$ = str(getarg(0));
+ .@x1 = getarg(1);
+ .@y1 = getarg(2);
+ .@x2 = getarg(3);
+ .@y2 = getarg(4);
+ .@size = getarraysize(.WorldDigRect_Map$);
+ .WorldDigRect_Map$[.@size] = .@map$;
+ .WorldDigRect_x1[.@size] = .@x1;
+ .WorldDigRect_y1[.@size] = .@y1;
+ .WorldDigRect_x2[.@size] = .@x2;
+ .WorldDigRect_y2[.@size] = .@y2;
+ return 1;
+ }
+
+ function AddMapDigRect {
+ .@m$=getarg(0);
+ .@x=getmapinfo(MAPINFO_SIZE_X, .@m$)-20;
+ .@y=getmapinfo(MAPINFO_SIZE_Y, .@m$)-20;
+ return AddDigRect(.@m$, 20, 20, .@x, .@y);
+ }
+
+ function PlayerIsTired {
+ if (is_evtc())
+ return false; // event coordinators are never tired
+
+ .@tick = gettimetick(1);
+ .@playertick = .PlayerTiredTime - readparam(bStr);
+ if (@ShovelLastUsed + max(4, .@playertick) > .@tick)
+ {
+ narrator S_FIRST_BLANK_LINE,
+ l("You are exhausted, you should rest a bit.");
+ return true;
+ }
+ @ShovelLastUsed = .@tick;
+ return false;
+ }
+
+ function Dig {
+ getmapxy(.@map$, .@x, .@y, 0);
+ for (.@i = 0; .@i < getarraysize($WorldBuriedTreasures_id); .@i++)
+ {
+ if (!strcmp($WorldBuriedTreasures_map$[.@i], .@map$) &&
+ $WorldBuriedTreasures_x[.@i] == .@x &&
+ $WorldBuriedTreasures_y[.@i] == .@y)
+ {
+ .@id = $WorldBuriedTreasures_id[.@i];
+ .@amount = $WorldBuriedTreasures_amount[.@i];
+ deletearray $WorldBuriedTreasures_id[.@i], 1;
+ deletearray $WorldBuriedTreasures_amount[.@i], 1;
+ deletearray $WorldBuriedTreasures_map$[.@i], 1;
+ deletearray $WorldBuriedTreasures_x[.@i], 1;
+ deletearray $WorldBuriedTreasures_y[.@i], 1;
+ getitem .@id, .@amount;
+ narrator S_FIRST_BLANK_LINE,
+ l("You found something!"),
+ l("It's @@ @@.", .@amount, getitemname(.@id));
+ return 1;
+ }
+ }
+ narrator S_FIRST_BLANK_LINE, l("Sadly, you found nothing but dirt.");
+ return 0;
+ }
+
+ function Bury {
+ narrator S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE, l("What would you like to bury?");
+ .@items$ = "";
+
+ mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
+
+ .@id = requestitem();
+
+ // If ID is invalid, there's not enough items, it is an Iron Shovel, it is bound = Cannot bury
+ // NOBODY bypass notrade check. (ITR_NONE is 0)
+ if (.@id < 1) close;
+ if (.@id < 1 || countitem(.@id) < 1 || .@id == IronShovel || checkbound(.@id) ||
+ (!getiteminfo(.@id, ITEMINFO_TRADE))
+ ) {
+ @ShovelLastUsed = 0;
+ if (.@id == IronShovel || .@id == SteelShovel || checkbound(.@id))
+ mesc l("You cannot bury this item!");
+ else if (!getiteminfo(.@id, ITEMINFO_TRADE))
+ mesc l("This item is too precious, you cannot part with it!");
+ else
+ mesc l("You give up.");
+ close;
+ return;
+ }
+
+ .@amount = 1;
+ if (countitem(.@id) > 1)
+ {
+ narrator S_FIRST_BLANK_LINE | S_LAST_BLANK_LINE, l("Amount?");
+ input .@amount, 1, countitem(.@id);
+ }
+
+ getmapxy(.@map$, .@x, .@y, 0);
+
+ delitem .@id, .@amount;
+ .@wtc = getarraysize($WorldBuriedTreasures_id);
+ $WorldBuriedTreasures_id[.@wtc] = .@id;
+ $WorldBuriedTreasures_amount[.@wtc] = .@amount;
+ $WorldBuriedTreasures_map$[.@wtc] = .@map$;
+ $WorldBuriedTreasures_x[.@wtc] = .@x;
+ $WorldBuriedTreasures_y[.@wtc] = .@y;
+ narrator S_FIRST_BLANK_LINE, l("You buried @@ @@.", .@amount, getitemname(.@id));
+
+ return true;
+ }
+
+ function ShovelQuests {
+ getmapxy(.@map$, .@x, .@y, 0);
+ for (.@i = 0; .@i < getarraysize(ShovelQuests_func$); .@i++)
+ {
+ if (!strcmp(ShovelQuests_map$[.@i], .@map$) &&
+ ShovelQuests_x[.@i] == .@x &&
+ ShovelQuests_y[.@i] == .@y)
+ {
+ .@func$ = ShovelQuests_func$[.@i];
+ deletearray ShovelQuests_func$[.@i], 1;
+ deletearray ShovelQuests_map$[.@i], 1;
+ deletearray ShovelQuests_x[.@i], 1;
+ deletearray ShovelQuests_y[.@i], 1;
+ callfunc(.@func$);
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+OnUse:
+ if (!CheckDigLocation())
+ end;
+
+ narrator S_LAST_BLANK_LINE,
+ l("You hold the shovel in your hands."),
+ l("What are you going to do?");
+
+ .@action = select(
+ l("Dig."),
+ l("Bury."),
+ l("Nothing."));
+
+ switch(.@action)
+ {
+ case 1:
+ if (PlayerIsTired())
+ close;
+ if (!ShovelQuests())
+ Dig();
+ break;
+ case 2:
+ if (PlayerIsTired())
+ close;
+ Bury();
+ break;
+ case 3:
+ narrator S_FIRST_BLANK_LINE, l("You hide your shovel.");
+ break;
+ }
+ close;
+
+OnHour00:
+ if (playerattached())
+ @ShovelLastUsed = 0;
+ end;
+
+OnInit:
+ .PlayerTiredTime = 20;
+
+ // Partial maps
+ AddDigRect("001-1", 172, 26, 200, 48);
+ AddDigRect("001-1", 198, 60, 201, 63);
+ AddDigRect("008-1-1", 32, 42, 46, 88);
+ AddDigRect("008-1-2", 40, 52, 114, 146);
+ AddDigRect("012-1", 44, 21, 139, 47);
+
+ // Whole maps
+ AddMapDigRect("008-1");
+ AddMapDigRect("008-3-5");
+ AddMapDigRect("012-3-1");
+ end;
+
+}
+
+function script shovel_addquest {
+ if (getargcount() < 4)
+ {
+ consolemes(CONSOLEMES_ERROR, "usage: shovel_addquest(map$,x,y,func$)");
+ return 0;
+ }
+ .@map$ = str(getarg(0));
+ .@x = getarg(1);
+ .@y = getarg(2);
+ .@func$ = str(getarg(3));
+ .@size = getarraysize(ShovelQuests_func$);
+ ShovelQuests_func$[.@size] = .@func$;
+ ShovelQuests_map$[.@size] = .@map$;
+ ShovelQuests_x[.@size] = .@x;
+ ShovelQuests_y[.@size] = .@y;
+ return 1;
+}
+
+function script shovel_adddigrect {
+ if (getargcount() < 5)
+ {
+ consolemes(CONSOLEMES_ERROR, "usage: shovel_adddigrect(map$,x1,y1,x2,y2)");
+ return 0;
+ }
+ .@map$ = str(getarg(0));
+ .@x1 = getarg(1);
+ .@y1 = getarg(2);
+ .@x2 = getarg(3);
+ .@y2 = getarg(4);
+ .@size = getarraysize(getvariableofnpc(.WorldDigRect_Map$, strnpcinfo(3)));
+ set getvariableofnpc(.WorldDigRect_Map$[.@size], strnpcinfo(3)), .@map$;
+ set getvariableofnpc(.WorldDigRect_x1[.@size], strnpcinfo(3)), .@x1;
+ set getvariableofnpc(.WorldDigRect_y1[.@size], strnpcinfo(3)), .@y1;
+ set getvariableofnpc(.WorldDigRect_x2[.@size], strnpcinfo(3)), .@x2;
+ set getvariableofnpc(.WorldDigRect_y2[.@size], strnpcinfo(3)), .@y2;
+ return 1;
+}
+
+// [Treasure Map] functions
+
+function script shovel_getcity {
+ .@a$=getarg(0);
+
+ // else is not required (return prevails)
+ if (.@a$ == "001-1")
+ return l("Artis East Beach");
+ if (.@a$ == "008-1")
+ return l("East Woodlands");
+ if (.@a$ == "008-1-1")
+ return l("West Woodland Beach");
+ if (.@a$ == "008-1-2")
+ return l("Swamps");
+ if (.@a$ == "008-3-5")
+ return l("Hurnscald Bandit Cave");
+ if (.@a$ == "012-1")
+ return l("Candor North");
+ if (.@a$ == "012-3-1")
+ return l("Candor Main Cave");
+
+ return .@a$;
+}
+
+function script shovel_randomtreasure {
+ .@id=any(TreasureKey,CoinBag,CoinBag,CoinBag,Coal,
+ Diamond,Ruby,Emerald,Sapphire,Topaz,Amethyst,
+ CrudeDiamond,CrudeRuby,CrudeEmerald,
+ CrudeSapphire,CrudeTopaz,CrudeAmethyst,
+ MaggotSlimePotion, LargeMana, LargeHealing);
+ delitem TreasureMap, 1;
+ .@amount=any(1,1,2);
+ // Very Commons
+ if (.@id == CoinBag || .@id == MaggotSlimePotion || .@id == TreasureKey)
+ .@amount+=any(0,1,0,1,2);
+ // Super commons
+ if (.@id == LargeMana || .@id == LargeHealing)
+ .@amount+=rand2(0,8);
+ // Rares
+ if (.@id == Coal)
+ .@amount=1;
+ getitem .@id, .@amount;
+ ShovelQuests_AssignedMAP$="";
+ ShovelQuests_AssignedX=0;
+ ShovelQuests_AssignedY=0;
+
+ mesn strcharinfo(0);
+ mesc l("You found something!");
+ mesc l("It's %d %s.", .@amount, getitemlink(.@id));
+ next;
+ closeclientdialog;
+ return;
+}
+
+function script shovel_genrandtreasure {
+ .@m$=any("008-1", "008-1-1", "008-1-2", "008-3-5",
+ "012-1", "012-3-1");
+
+ // Prepare good defaults
+ .@x1=.@y1=20;
+ .@x2=getmapinfo(MAPINFO_SIZE_X, .@m$)-20;
+ .@y2=getmapinfo(MAPINFO_SIZE_Y, .@m$)-20;
+
+ // Default overrides
+ if (.@m$ == "008-1-1") {
+ // West Woodland Beach
+ .@x1=32; .@y1=42;
+ .@x2=46; .@y2=88;
+ } else if (.@m$ == "008-1-2") {
+ // Swamps
+ .@x1=40; .@y1=52;
+ .@x2=114; .@y2=146;
+ } else if (.@m$ == "012-1") {
+ // Candor North
+ .@x1=44; .@y1=139;
+ .@x2=21; .@y2=47;
+ }
+
+ // Dangerous, but I never had issues with this
+ do {
+ .@x=rand2(.@x1, .@x2);
+ .@y=rand2(.@y1, .@y2);
+ } while (!checkcell(.@m$, .@x, .@y, cell_chkpass));
+
+ // Success
+ if (checkcell(.@m$, .@x, .@y, cell_chkpass)) {
+ shovel_addquest(.@m$, .@x, .@y, "shovel_randomtreasure");
+ ShovelQuests_AssignedMAP$=shovel_getcity(.@m$);
+ ShovelQuests_AssignedX=.@x;
+ ShovelQuests_AssignedY=.@y;
+ }
+ return;
+}
+
+