diff options
author | Jesusaves <cpntb1@ymail.com> | 2021-04-09 11:00:49 -0300 |
---|---|---|
committer | Jesusaves <cpntb1@ymail.com> | 2021-04-09 11:00:49 -0300 |
commit | 8a4bf716002a017de77fe7df301ef8e4aaf00a2e (patch) | |
tree | 4947d0b015baad639fa07133369e9a09c8a468bc /npc/items | |
download | serverdata-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.txt | 22 | ||||
-rw-r--r-- | npc/items/croconut.txt | 72 | ||||
-rw-r--r-- | npc/items/gift.txt | 35 | ||||
-rw-r--r-- | npc/items/master_skillbook.txt | 164 | ||||
-rw-r--r-- | npc/items/music_toys.txt | 18 | ||||
-rw-r--r-- | npc/items/rand_sc_heal.txt | 85 | ||||
-rw-r--r-- | npc/items/recipes.txt | 352 | ||||
-rw-r--r-- | npc/items/shovel.txt | 361 |
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; +} + + |