diff options
-rw-r--r-- | world/map/db/item_db.conf | 4 | ||||
-rw-r--r-- | world/map/db/item_db_use.txt | 4 | ||||
-rw-r--r-- | world/map/db/mob_db.conf | 17 | ||||
-rw-r--r-- | world/map/db/mob_db_over_150.txt | 4 | ||||
-rw-r--r-- | world/map/npc/functions/treasure_hunt.txt | 469 | ||||
-rw-r--r-- | world/map/npc/items/maps.txt | 3 | ||||
-rw-r--r-- | world/map/npc/items/shovel.txt | 4 | ||||
-rw-r--r-- | world/map/npc/scripts.conf | 1 |
8 files changed, 486 insertions, 20 deletions
diff --git a/world/map/db/item_db.conf b/world/map/db/item_db.conf index eb0325dd..4d006e21 100644 --- a/world/map/db/item_db.conf +++ b/world/map/db/item_db.conf @@ -17101,7 +17101,7 @@ item_db: ( KeepAfterUse: true Trade: { notrade: true - nodrop: true + nodrop: false nocart: true nomail: true noauction: true @@ -17132,7 +17132,7 @@ item_db: ( KeepAfterUse: true Trade: { notrade: true - nodrop: true + nodrop: false nocart: true nomail: true noauction: true diff --git a/world/map/db/item_db_use.txt b/world/map/db/item_db_use.txt index 5bb8137c..020bc80b 100644 --- a/world/map/db/item_db_use.txt +++ b/world/map/db/item_db_use.txt @@ -150,5 +150,5 @@ 5382, AnchorStone, 0, 90000, 45000, 40, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 23, {set @StoneName$, "AnchorStone"; callfunc "useAnchorStone";}, {} //ID, Name, Type, Price, Sell, Weight, ATK, DEF, Range, Mbonus, Slot, Gender, Loc, wLV, eLV, View, Mode, {UseScript}, {EquipScript} 5383, AnchoredAnchorStone, 0, 0, 0, 40, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 31, {set @StoneName$, "AnchoredAnchorStone"; callfunc "useAnchorStone";}, {} -5405, LegendaryShovel, 0, 0, 0, 210, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 23, {set @ShovelName$, "LegendaryShovel"; callfunc "useShovel";}, {} -5406, LegendaryTreasureMap, 0, 0, 0, 14, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 23, {set @MapName$, "LegendaryTreasureMap"; callfunc "readMap";}, {} +5405, LegendaryShovel, 0, 0, 0, 210, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 22, {set @ShovelName$, "LegendaryShovel"; callfunc "useShovel";}, {} +5406, LegendaryTreasureMap, 0, 0, 0, 14, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 22, {set @MapName$, "LegendaryTreasureMap"; callfunc "readMap";}, {} diff --git a/world/map/db/mob_db.conf b/world/map/db/mob_db.conf index 21a59413..256c8e99 100644 --- a/world/map/db/mob_db.conf +++ b/world/map/db/mob_db.conf @@ -3928,13 +3928,8 @@ mob_db: ( MutationCount: 1 MutationStrength: 10 Drops: { - TreasureKey: 800 - UndeadEar: 150 - UndeadEye: 150 - RottenRags: 70 - Soul: 50 BlackRose: 30 - MagicRing: 4 + MagicRing: 2 BlinkingHocus: 1 } }, @@ -3981,13 +3976,11 @@ mob_db: ( MutationCount: 1 MutationStrength: 10 Drops: { - TreasureKey: 800 - UndeadEar: 90 - UndeadEye: 80 - RottenRags: 70 - Soul: 50 + Arrow: 5000 + IronArrow: 5000 + SilverArrow: 50 BlackRose: 30 - EnchantersAmulet: 2 + EnchantersAmulet: 1 } }, { diff --git a/world/map/db/mob_db_over_150.txt b/world/map/db/mob_db_over_150.txt index 00c50972..a77baaa5 100644 --- a/world/map/db/mob_db_over_150.txt +++ b/world/map/db/mob_db_over_150.txt @@ -23,8 +23,8 @@ 1146, Flashmob, Flashmob, 181, 27000, 280, 72000, 5000, 3, 40, 60, 57, 57, 0, 31, 22, 90, 127, 255, 95, 31, 10, 1, 1, 37, 181, 160, 600, 672, 50, 825, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1147, Koyntety, Koyntety, 181, 27000, 280, 72000, 5000, 4, 220, 240, 52, 52, 0, 31, 22, 90, 127, 255, 105, 31, 10, 1, 1, 37, 181, 240, 1400, 672, 50, 825, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //ID, Name, Jname, LV, HP, SP, EXP, JEXP, Range1, ATK1, ATK2, DEF, MDEF, CRITDEF,STR, AGI, VIT, INT, DEX, LUK, Range2, Range3, Scale, Race, Element,Mode, Speed, Adelay, Amotion,Dmotion,Drop0id,Drop0%, Drop1id,Drop1%, Drop2id,Drop2%, Drop3id,Drop3%, Drop4id,Drop4%, Drop5id,Drop5%, Drop6id,Drop6%, Drop7id,Drop7%, Drop8id,Drop8%, Drop9id,Drop9%, Item1, Item2, MEXP, ExpPer, MVP1id, MVP1per,MVP2id, MVP2per,MVP3id, MVP3per,mutationcount,mutationstrength -1148, DoomGolem, DoomGolem, 180, 22000, 280, 65000, 2000, 3, 160, 180, 60, 30, 0, 31, 22, 90, 127, 255, 105, 31, 10, 1, 1, 37, 181, 320, 1000, 672, 50, 537, 800, 779, 150, 780, 150, 777, 70, 1198, 50, 666, 30, 5253, 4, 5258, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10 -1149, Enchanter, Enchanter, 181, 19000, 280, 55000, 2000, 8, 140, 180, 30, 60, 0, 31, 22, 90, 127, 255, 105, 31, 10, 1, 1, 37, 181, 240, 800, 672, 50, 537, 800, 779, 90, 780, 80, 777, 70, 1198, 50, 666, 30, 1227, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10 +1148, DoomGolem, DoomGolem, 180, 22000, 280, 65000, 2000, 3, 160, 180, 60, 30, 0, 31, 22, 90, 127, 255, 105, 31, 10, 1, 1, 37, 181, 320, 1000, 672, 50, 666, 30, 5253, 2, 5258, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10 +1149, Enchanter, Enchanter, 181, 19000, 280, 55000, 2000, 8, 140, 180, 30, 60, 0, 31, 22, 90, 127, 255, 105, 31, 10, 1, 1, 37, 181, 240, 800, 672, 50, 1199, 5000, 529, 5000, 5290, 50, 666, 30, 1227, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10 1150, ManaTyrant, ManaTyrant, 180, 24000, 280, 27000, 5000, 2, 300, 325, 42, 67, 0, 31, 22, 90, 127, 255, 95, 31, 10, 1, 1, 37, 181, 180, 1050, 672, 50, 759, 1, 5237, 20, 1253, 5, 720, 100, 825, 500, 868, 20, 1172, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1161, Xakelbael, Xakelbael, 200, 29999, 280, 999999, 99999, 9, 90, 124, 74, 100, 0, 199, 2, 199, 197, 255, 175, 31, 10, 1, 1, 37, 181, 210, 672, 672, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1170, CrystalGolem, CrystalGolem, 180, 25000, 280, 68000, 2200, 3, 170, 190, 75, 40, 0, 35, 26, 99, 127, 255, 105, 31, 30, 1, 0, 46, 169, 320, 1000, 672, 50, 5384, 400, 5384, 200, 5384, 100, 4002, 50, 4003, 50, 4004, 50, 4005, 50, 4006, 50, 4007, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/world/map/npc/functions/treasure_hunt.txt b/world/map/npc/functions/treasure_hunt.txt new file mode 100644 index 00000000..0e97adce --- /dev/null +++ b/world/map/npc/functions/treasure_hunt.txt @@ -0,0 +1,469 @@ +// Pirate Treasures Hunt quest (c) 2025 Hello=) + +// This NPC handles treasure placement +-|script|TreasureHunt|32767 +{ + end; + +OnTreasurePlace: + if (GM < 60) end; + gmlog strcharinfo(0) + " shuffled treasure placement"; + wgm strcharinfo(0) + " shuffled treasure placement"; + set $TREASURE_X, 0; // To force reinit + void call("treasure_place"); + end; + +OnInit: + registercmd "@treasure_place", "TreasureHunt::OnTreasurePlace"; + void call("treasure_place"); + end; +} + +// Applies defaults to global vars if unconfigured +function|script|treasure_place +{ + if ($TREASURE_MAP$ == "") || !($TREASURE_X) || !($TREASURE_Y) // Not looks configured? + goto L_Setup; + return; + +L_Setup: + // Apply defaults + set $TREASURE_REWARD, Eyepatch; // main reward + set $TREASURE_BOOTY, 200; // max amount of booty (worst case anti-milking cap) + set $TREASURE_DIFFICULTY, 100; // common rounds difficulty + set $TREASURE_DIFFICULTY2, 100; // extra rounds difficulty (if player found treasure) + set $TREASURE_MAP$, "003-4"; // Map to use. Ships are hardwired so far, beware. + set $TREASURE_X1, 97; // Rectangle + set $TREASURE_X2, 104; + set $TREASURE_Y1, 61; + set $TREASURE_Y2, 100; + // $TREASURE_DEBUG // Debug mode, a lot of battle flow/trace spam. + // $TREASURE_TURBO // Play battle real fast. You'll need @hide and GM Hat to survive. + goto L_TryPlacement; + +L_TryPlacement: + // Try placement + set $TREASURE_X, rand($TREASURE_X1, $TREASURE_X2); // Choose exact spot + set $TREASURE_Y, rand($TREASURE_Y1, $TREASURE_Y2); + if (iscollision($TREASURE_MAP$, $TREASURE_X, $TREASURE_Y)) + goto L_TryPlacement; // do not place trasure on collisions + debugmes "treasure_place: treasure placed and configured"; + return; +} + +// Handler to be invoked from item usage attempt of shovels. +// This function supposed to be called with player RID attached (its item use by player) +// Input: Arg0: shovel name from item use handler function. +// Return: 1 = item use handled (swallowed) by quest, 0 = not handled. +function|script|treasure_try_shovel +{ + set .@shovel$, getarg(0, ""); + set .@handled, 0; + if ($TREASURE_DEBUG) debugmes "treasure_try_shovel, shovel=" + .@shovel$; + if (.@shovel$ == "LegendaryShovel") set .@handled, 1; // TH handles everything about Legendary Shovel + if (!(.@handled) && (getmap() == $TREASURE_MAP$)) // Hint player they need different shovel on treasure map + message strcharinfo(0), "There're rocks in these sands. You'll need different shovel here..."; + if ($TREASURE_DEBUG) debugmes "treasure_try_shovel, .@handled=" + .@handled; + if (.@handled) addtimer 0, "TreasureDig::OnDig", BL_ID; // Request NPC to do its thing just like #treasuredig. + return .@handled; +} + +// Handler to be invoked from item usage attempt of maps. +// This function supposed to be called with player RID attached (its item use by player) +// Input: Arg0: map name from item use handler function. +// Return: 1 = item use handled (swallowed) by quest, 0 = not handled. +function|script|treasure_try_map +{ + set .@mapname$, getarg(0, ""); + if ($TREASURE_DEBUG) debugmes "treasure_try_map, map=" + .@mapname$; + set .@handled, 0; + if (.@mapname$ == "LegendaryTreasureMap") set .@handled, 1; // TH handles everything about Legendary Treasure Map + if ($TREASURE_DEBUG) debugmes "treasure_try_map, .@handled=" + .@handled; + if ((getmap() != $TREASURE_MAP$) && (.@handled)) + message strcharinfo(0), "Treasure Map : This place doesn't looks like one on map."; + if ((getmap() == $TREASURE_MAP$) && (.@handled) && + !(isin($TREASURE_MAP$, $TREASURE_X1, $TREASURE_Y1, $TREASURE_X2, $TREASURE_Y2))) + message strcharinfo(0), "Treasure Map : This place looks right! Yet [X] mark isn't where you stand."; + if ((getmap() == $TREASURE_MAP$) && (.@handled) && + (isin($TREASURE_MAP$, $TREASURE_X1, $TREASURE_Y1, $TREASURE_X2, $TREASURE_Y2))) + message strcharinfo(0), "Treasure Map : Aha! Right spot! Unfortunately X mark is big and crude. Promising area is " + + "(" + $TREASURE_X1 +"," + $TREASURE_Y1 + ")<->(" + $TREASURE_X2 + "," + $TREASURE_Y2 + ")"; + return .@handled; +} + +// This NPC handles traeasure dig. +-|script|TreasureDig|32767 +{ + end; + +OnDig: + if ($TREASURE_DISABLE) message strcharinfo(0), "Tough luck, seems there's no booty at this time!"; + if ($TREASURE_DISABLE) end; + set @treasureMobs, + mobcount($TREASURE_MAP$, "TreasureDigAux::OnMobKill") + + mobcount($TREASURE_MAP$, "TreasureDigAux::OnPirateKill"); + if ($TREASURE_DEBUG) debugmes "OnDig: mob count = " + @treasureMobs; + if (@treasureMobs > 300) message strcharinfo(0), "Its too crowded here to dig! Perhaps kill some mob first?"; + if (@treasureMobs > 300) end; // Do not let users spam server by mobs indefinitely + set .@puppet$, "#"+strnpcinfo(0)+"#"+BL_ID; + set .@puppet, puppet(getmap(), POS_X, POS_Y, .@puppet$, 127); + if (.@puppet < 1) end; // It also denies player launching N instances at once. + // Set up instance of treasure hunt attempt + set .digger, BL_ID, .@puppet; + set .diggernm$, strcharinfo(0), .@puppet; + set .delay, 1000, .@puppet; // Initial round delay + set .tiles, TILES_WALKED, .@puppet; + if ($TREASURE_DEBUG) debugmes "OnDig: starting"; + npctalk .@puppet$, "Digging : " + strcharinfo(0) + " starts digging in hope to find something.."; + if ($TREASURE_MAP$ == getmap()) + addnpctimer 4000, .@puppet$+"::OnDiggingRound"; // Start digging rounds. + else + addnpctimer 12000, .@puppet$+"::OnDiggingRound"; // Start digging rounds - fake - slow 'em a bit. + addnpctimer 700000, .@puppet$+"::OnDestroy"; // Failsafe quest shutdown on timeout + end; + +OnDiggingRound: + set .dig_round, .dig_round + 1; + if ($TREASURE_DEBUG) debugmes "OnDiggingRound: my name=" + strnpcinfo(0) + " digger=" + .digger; + if ($TREASURE_DEBUG) debugmes "OnDiggingRound: PLAYER: POSX=" + get(POS_X, .digger) + " POSY=" + get(POS_Y, .digger) + " MAP=" + getmap(.digger) + " TILES=" + get(TILES_WALKED, .digger); + if ($TREASURE_DEBUG) debugmes "OnDiggingRound: NPC: POSX=" + getnpcx() + " POSY=" + getnpcy() + " MAP=" + strnpcinfo(3) + " TILES=" + .tiles; + if (!(isloggedin(.digger))) set .failed, 2; // Treasure digger disappeared? + if (get(Hp, .digger) < 1) set .failed, 3; // Digger digger died? + if ((getmap(.digger) != strnpcinfo(3)) || // Digger left map? + (get(POS_X, .digger) != getnpcx()) || + (get(POS_Y, .digger) != getnpcy()) || + (get(TILES_WALKED, .digger) != .tiles)) + set .failed, 4; // Has digger moved? + if ($TREASURE_MAP$ != strnpcinfo(3)) set .failed, 9; // Trying to dig on wrong map? Side effects avoidance. + if ($TREASURE_DEBUG) debugmes "OnDiggingRound: failed1=" + .failed; + if (.failed) goto L_DiggFail; + // Basic checks ok -> next round starts + misceffect FX_CHANNELLING_RAISE_RED, strcharinfo(0, .digger); + set .failed, call("treasure_dig_round", .dig_round); // core function of digging + if ($TREASURE_DEBUG) debugmes "OnDiggingRound: failed2=" + .failed; + if !($TREASURE_TURBO) set .delay, .delay + 1000; // Turbo == "skip AI moves" for test/debug: FAST battle, @hide+gm map to observe + if ((.failed == 9) && call("treasure_is_here") && ($TREASURE_REWARD != 0)) + goto L_DiggFound; // MaxRound && Found treasure?! Its WIN, not .fail :) + if ((.failed == 9) && call("treasure_is_here") && ($TREASURE_REWARD == 0)) + set .failed, 10; // Found it - but someone got there first? How unfortunate. + if (.failed) goto L_DiggFail; // catches e.g. (running to max round && no treasure) + else addnpctimer .delay, strnpcinfo(0)+"::OnDiggingRound"; + end; + +// Invoked when digging failed for any reason, by both OnDiggingRound and OnBootyRound. +L_DiggFail: + if ($TREASURE_DEBUG) debugmes "TreasureDig: digging done, .failed=" + .failed; + if (.failed == 2) npctalk strnpcinfo(0), "Digging : ##3##BDigger " + .diggernm$ + " disappeared... strange..."; + elif (.failed == 3) npctalk strnpcinfo(0), "Digging : ##3##BDigger " + .diggernm$ + " haven't made it, digging site collapsed"; + elif (.failed == 4) npctalk strnpcinfo(0), "Digging : ##3##BDigger " + .diggernm$ + " has lost focus and digging site collapsed"; + elif (.failed == 9) npctalk strnpcinfo(0), "Digging : ##3##BDoh! Seems there's no treasure on this spot!"; + elif (.failed == 10) npctalk strnpcinfo(0), "Digging : ##3##BDoh! Someone already digged treasure out!"; + else /*error, etc*/ npctalk strnpcinfo(0), "Digging : ##3##BDigger " + .diggernm$ + " something went wrong, digging site collapsed"; + destroy; + +L_DiggFound: + if !($TREASURE_TURBO) set .delay, 16000; // Configure booty rounds + else set .delay, 3000; + set .failed, 0; + set .round, 1; + monster $TREASURE_MAP$, 94, 74, "Pirates!", MontBlanc, 1, "TreasureDigAux::OnPirateKill"; // FIXME hardwired thing + monster $TREASURE_MAP$, 95, 66, "Pirates!", MontBlanc, 1, "TreasureDigAux::OnPirateKill"; + monster $TREASURE_MAP$, 97, 91, "Pirates!", MontBlanc, 1, "TreasureDigAux::OnPirateKill"; + mapannounce strnpcinfo(3), "Emo : WHAT DO WE HAVE HERE?! Contenders for OUR booty?! Pirates! Kill them all! YARRR!!", 0; + addnpctimer .delay, strnpcinfo(0)+"::OnBootyRound"; // Hand over -> OnBootyRound but do not destroy puppet. + end; + +// Invoked when digger survived initial digging && found treasure. Called when OnDiggRound rounds end. +OnBootyRound: + if ($TREASURE_DEBUG) debugmes "OnBootyRound ->"; + if (!(isloggedin(.digger))) set .failed, 2; // Treasure digger disappeared? + if (get(Hp, .digger) < 1) set .failed, 3; // Digger digger died? + if ((getmap(.digger) != strnpcinfo(3)) || // Digger left map? + (get(POS_X, .digger) != getnpcx()) || + (get(POS_Y, .digger) != getnpcy()) || + (get(TILES_WALKED, .digger) != .tiles)) + set .failed, 4; // Has digger moved? + if (.failed) goto L_DiggFail; // Reuse digg failure handling above. + if (.round > 8) goto L_Finalize; + npctalk strnpcinfo(0), "Digging : ##3##B [TREASURE] [" + .round + "] "+ .diggernm$ + " found treasure, keep digger alive to collect collateral!"; + if ($TREASURE_BOOTY > 0) + addtimer 0, "TreasureDigAux::OnCollateral10", .digger; // Collateral for supporters + set $TREASURE_BOOTY, $TREASURE_BOOTY - 10; // anti-milking cap, total ~20 rounds with booty top (configurable) + set .@round_power, call("treasure_estimate_team"); // get team level + if ($TREASURE_DEBUG) debugmes "treasure_dig_round: round power B0=" + .@round_power; + set .@round_power, (.@round_power * $TREASURE_DIFFICULTY2) / 170 + (.round / 7) + rand(3); // Adjust & randomize + if ($TREASURE_DEBUG) debugmes "treasure_dig_round: round power B1=" + .@round_power; + if (.round == 1) set .@mob, Emo; // Guy who yelled + else set .@mob, Ratto; // His ship ratto, also treasure contender + void call("spawn_in_radius", strnpcinfo(3), getnpcx(), getnpcy(), 2, .@mob, 1, "TreasureDigAux::OnPirateKill"); + void call("spawn_in_radius", strnpcinfo(3), getnpcx(), getnpcy(), 4, Swashbuckler, .@round_power, "TreasureDigAux::OnPirateKill"); + void call("spawn_in_radius", strnpcinfo(3), getnpcx(), getnpcy(), 4, Grenadier, .@round_power, "TreasureDigAux::OnPirateKill"); + void call("spawn_in_radius", strnpcinfo(3), getnpcx(), getnpcy(), 4, Thug, .@round_power, "TreasureDigAux::OnPirateKill"); + void call("spawn_in_radius", strnpcinfo(3), getnpcx(), getnpcy(), 4, Ratto, 5, "TreasureDigAux::OnPirateKill"); + set .round, .round + 1; + addnpctimer .delay, strnpcinfo(0)+"::OnBootyRound"; // Hand over -> OnBootyRound but do not destroy puppet. + end; + +L_Finalize: + addtimer 0, "TreasureDigAux::OnMainBooty", .digger; // Hand over to final reward handler. + mapannounce strnpcinfo(3), "Treasure : Digger " + .diggernm$ + " found treasure!", 0; + npctalk strnpcinfo(0), "Digging : ##3##B [TREASURE] Victory! Treasure hunter " + .diggernm$ + " got booty!"; + destroy; + +OnDestroy: + debugmes "TreasureDig: GLOBAL TIME OUT, this shouldn't happen"; // Failsafe logic + npctalk strnpcinfo(0), "Digging : ##3##BSomething went wrong, your digging site has collapsed"; + destroy; + +OnInit: + end; +} + +// This function only meant to be called by TreasureDig's puppet. +// Main digging round handling logic happens here, spawns + dig fallouts +// Input: Arg0: round # +// Arg1: players str +// Returns: 0 if all ok, 1 = failure, 9 = max round reached. +function|script|treasure_dig_round +{ + set .@round, getarg(0, -1); + set .@res, 0; // > 0 halts next rounds, 1 = failure, 9 = "failed to find treasure" + set .@rounds0, 2; // # of rounds configuration. + set .@rounds1, 6; + set .@rounds2, 12; + set .@rounds3, 18; + set .@rounds4, 22; + if ($TREASURE_DEBUG) debugmes "treasure_digg_round: round # " +.@round + " r4=" + .@rounds4; + if (.@round < 1) goto L_Failed; + if ((.@round >= .@rounds4)) goto L_Done; + setarray .@mobs_0[0], CaveMaggot, HouseMaggot, VoidMaggot, Ratto; // Mobs for round spawns + setarray .@mobs_1[0], AngryScorpion, Hyvern, Snake, Spider, Archant, RedSlime, AngrySeaSlime, AngryGreenSlime; + setarray .@mobs_2[0], VoidSnake, MountainSnake, GrassSnake, SoulSnake, BlackScorpion, CrotcherScorpion, VoidBat, HuntsmanSpider; + setarray .@mobs_3[0], Skeleton, LadySkeleton, Wight, RedBone, SoulEater; + setarray .@mobs_4[0], Thug, Swashbuckler, Grenadier; + if (.@round <= .@rounds0) set .@mobID, .@mobs_0[rand(getarraysize(.@mobs_0))]; // Pick random mob for i-th round + elif (.@round <= .@rounds1) set .@mobID, .@mobs_1[rand(getarraysize(.@mobs_1))]; // Make mobs progressiveky harder + elif (.@round <= .@rounds2) set .@mobID, .@mobs_2[rand(getarraysize(.@mobs_2))]; + elif (.@round <= .@rounds3) set .@mobID, .@mobs_3[rand(getarraysize(.@mobs_3))]; + elif (.@round <= .@rounds4) set .@mobID, .@mobs_4[rand(getarraysize(.@mobs_4))]; + else set .@mobID, MobMoubootaur; // Failsafe :) + set .@rand, rand(1, 100); // Does digging site blows up, releases poison or stays stable? + if (.@rand < 22) set .@dig_action$, "treasure_dig_poison"; + elif (.@rand > 78) set .@dig_action$, "treasure_dig_blowup"; + else /* 30..70 */ set .@dig_action$, "treasure_dig_stable"; + if ($TREASURE_DEBUG) debugmes "treasure_digg_round: round # " + .dig_round + " .@rand=" + .@rand + " .@dig_action$=" + .@dig_action$; + void call(.@dig_action$, .dig_round); // Avoids goto spaghetti but chosen func MUST exist, or server WILL crash! + set .@round_power, call("treasure_estimate_team"); // get team level + if ($TREASURE_DEBUG) debugmes "treasure_dig_round: round power0=" + .@round_power; + set .@round_power, (.@round_power * $TREASURE_DIFFICULTY) / 130 + (.@round / 7) + rand(3); // Adjust & randomize + if ($TREASURE_DEBUG) debugmes "treasure_dig_round: round power1=" + .@round_power; + addtimer 0, "TreasureDigAux::OnCollateral1", .digger; + void call("spawn_in_radius", strnpcinfo(3), getnpcx(), getnpcy(), 4, .@mobID, .@round_power, "TreasureDigAux::OnMobKill"); + // Show some fancy messages + if (.@round <= .@rounds2) npctalk strnpcinfo(0), "Digging : [" +.@round + "] " + .diggernm$ + " hit monster nest!"; + elif (.@round <= .@rounds3) npctalk strnpcinfo(0), "Digging : [" +.@round + "] " + .diggernm$ + " Yuck! Skeleton I found moves!"; + elif (.@round <= .@rounds4) npctalk strnpcinfo(0), "Digging : [" +.@round + "] " + .diggernm$ + " pirates got curious what this noise all about"; + else npctalk strnpcinfo(0), "Digging : [" +.@round + "] " + .diggernm$ + " ?!?!?!"; + return 0; + +L_Done: + if ($TREASURE_DEBUG) debugmes "treasure_digg_round: rounds done"; + return 9; // Inform quest max rounds reached and no treasure been found. + +L_Failed: + debugmes "treasure_digg_round: call failed, arg0=" + getarg(0) + "arg1=" + getarg(1); + return 1; +} + +// This spawns mobs in a given radius. Fallbacks to spot it it not fits map. +// This function can be called in any context. +// Input: Arg0: map where to spawn +// Arg1: X +// Arg2: Y +// Arg3: Radius +// Arg4: Mob id +// Arg5: # of mobs +// Arg6: Event for mob death (must be given, even as "") +function|script|spawn_in_radius +{ + set .@map$, getarg(0, ""); + set .@x, getarg(1, -1); + set .@y, getarg(2, -1); + set .@r, getarg(3, -1); + set .@mob, getarg(4, -1); + set .@qty, getarg(5, -1); + set .@evt$, getarg(6, ""); + // Args check. + if ((.@map$ == "") || (.@evt$ == "6") || (.@mob < 1) || + (.@x < 1) || (.@x > getmapmaxx(.@map$)) || (.@r < 1) || (.@qty < 1) || + (.@y < 1) || (.@y > getmapmaxy(.@map$))) + goto L_Fail; + // Does (x-r, y-r, x+r, y+r) rectangle fits map? + if ((.@x > .@r) && (.@y > .@r) && + ((.@x + .@r) < getmapmaxx(.@map$)) && + ((.@y + .@r) < getmapmaxy(.@map$))) //Enough room? Use area. + areamonster .@map$, (.@x-.@r), (.@y-.@r), (.@x+.@r), .@y+.@r, "", .@mob, .@qty, .@evt$; + else // Rectangle does not fits, fallback + monster .@map$, .@x, .@y, "", .@mob, .@qty, .evt$; + return; + +L_Fail: + debugmes "spawn_in_radius: call failed, arg0=" + getarg(0) + " arg1=" + getarg(1) + + " arg2=" + getarg(2) + " arg3=" + getarg(3) + " arg4=" + getarg(4) + + " arg5=" + getarg(5)+ " arg6=" + getarg(6); + return; +} + +// This function meant to be run in context of TreasureDig's *puppet* only +function|script|treasure_dig_poison +{ + if ($TREASURE_DEBUG) debugmes "TreasureDigg: dig_poison"; + npctalk strnpcinfo(0), "Digging : ["+getarg(0)+"] attempt to dig released poisonous gas!"; // Next throws events in digger (player) context + foreach 0, strnpcinfo(3), (getnpcx() - 7), (getnpcy() - 7), (getnpcx() + 7), (getnpcy() + 7), "TreasureDigAux::OnPoisonousGasPlayer", .digger; + foreach 2, strnpcinfo(3), (getnpcx() - 4), (getnpcy() - 4), (getnpcx() + 4), (getnpcy() + 4), "TreasureDigAux::OnPoisonousGasMob", .digger; + return; +} + +// This function meant to be run in context of TreasureDig's *puppet* only +function|script|treasure_dig_blowup +{ + if ($TREASURE_DEBUG) debugmes "TreasureDigg: dig_blowup"; + npctalk strnpcinfo(0), "Digging : ["+getarg(0)+"] underground gas bubble blows up!"; // Next throws events in digger (player) context + foreach 0, strnpcinfo(3), (getnpcx() - 7), (getnpcy() - 7), (getnpcx() + 7), (getnpcy() + 7), "TreasureDigAux::OnBlowUpPlayer", .digger; + foreach 2, strnpcinfo(3), (getnpcx() - 4), (getnpcy() - 4), (getnpcx() + 4), (getnpcy() + 4), "TreasureDigAux::OnBlowUpMob", .digger; + return; +} + +// This function meant to be run in context of TreasureDig's *puppet* only +function|script|treasure_dig_stable +{ + if ($TREASURE_DEBUG) debugmes "TreasureDigg: dig_stable"; + return; +} + +// This function meant to be run in context of TreasureDig's *puppet* only +function|script|treasure_is_here +{ + if ($TREASURE_DEBUG) debugmes "treasure_is_here ->"; + set .@res, 0; + if (($TREASURE_MAP$ == strnpcinfo(3)) && + ($TREASURE_X == getnpcx()) && + ($TREASURE_Y == getnpcy())) + set .@res, 1; + if ($TREASURE_DEBUG) debugmes "treasure_is_here <- .@res=" + .@res; + return .@res; +} + +// This function meant to be run in context of TreasureDig's *puppet* only +function|script|treasure_estimate_team +{ + if ($TREASURE_DEBUG) debugmes "treasure_estimate_team: ->"; + set @treasure_estimate_team, 1, .digger; // Prepare digger's context + if ($TREASURE_DEBUG) debugmes "team_est0 = " + get(@treasure_estimate_team, .digger); // This throws events in digger's context + foreach 0, strnpcinfo(3), (getnpcx() - 7), (getnpcy() - 7), (getnpcx() + 7), (getnpcy() + 7), "TreasureDigAux::OnPlayerEstimate", .digger; + if ($TREASURE_DEBUG) debugmes "team_est1 = " + get(@treasure_estimate_team, .digger); // This throws events in digger's context + return get(@treasure_estimate_team, .digger); +} + +// This NPC handles aux things like poisoning, blow up, statuses cleanup, items placement, ... +-|script|TreasureDigAux|32767 +{ + end; + +// This cleans players statues like leftovers of poison or blowup stunning. +// Invoked by timer set by site blowup/poison gas handlers +OnPlayerStatusCleanup: + if ($TREASURE_DEBUG) debugmes "TreasureDigAux: status cleanup, BL ID=" + BL_ID; + if (sc_check(SC_POISON)) sc_end SC_POISON; + if (sc_check(SC_SLOWMOVE)) sc_end SC_SLOWMOVE; + if (sc_check(SC_HALT_REGENERATE)) sc_end SC_HALT_REGENERATE; + end; + +// Dig site poisonous gas - invoked per player (hurts players) +OnPoisonousGasPlayer: +// debugmes "TreasureDigAux: poison/player, target ID=" + @target_id; + misceffect FX_EMOTE_DISGUST, strcharinfo(0, @target_id); + sc_start SC_POISON, 1, 60, @target_id; // Poison player + sc_start SC_HALT_REGENERATE, 5000, 0; // Even if fails, at least halt regen. + addtimer 5000, "TreasureDigAux::OnPlayerStatusCleanup"; // clean PC statuses + end; + +// Dig site poisonous gas - invoked per mob (aggravates mobs) +OnPoisonousGasMob: +// debugmes "TreasureDigAux: poison/mob, target ID=" + @target_id; + set .@type, get(Class, @target_id); // Dont poison undead + if ((.@type != Skeleton) && (.@type != LadySkeleton) && (.@type != Wight) && + (.@type != RedBone) && (.@type != SoulEater)) + sc_start SC_POISON, 1, 10, @target_id; // Poison MOBS, too. + aggravate @target_id; // This aggravates mobs. + end; + +// Dig site blow up - invoked per player (hurts players) +OnBlowUpPlayer: +// debugmes "TreasureDigAux: blowup/player, target ID=" + @target_id; + misceffect FX_MEDIUM_SMOKE, strcharinfo(0, @target_id); // Show slow effect + sc_start SC_SLOWMOVE, 3000, 300, @target_id; // Slow player temporarily + sc_start SC_HALT_REGENERATE, 5000, 0; // Stop regen temporarily + set Hp, (get(Hp, @target_id) * 2 / 3), @target_id; // Yes explosion hurts. + addtimer 5000, "TreasureDigAux::OnPlayerStatusCleanup"; // clean statuses + end; + +// Dig site blow up - invoked per mob (aggravates mobs) +OnBlowUpMob: +// debugmes "TreasureDigAux: blowup/mob, target ID=" + @target_id; + injure BL_ID, @target_id, get(Hp, @target_id) / 3; // Yes, explosion can hurt mobs, too! + aggravate @target_id; // This aggravates them! + end; + +// Event thrown when quest mobs die. +OnMobKill: + if ($TREASURE_DEBUG) debugmes "TreasureDigAux: mob killed, @mobID=" + @mobID; + end; + +OnPirateKill: + if ($TREASURE_DEBUG) debugmes "TreasureDigAux: pirate killed, @mobID=" + @mobID; + end; + +// Event invoked by team estimation function. +OnPlayerEstimate: + if (get(Hp, @target_id) > 0) set @treasure_estimate_team, @treasure_estimate_team + (get(BaseLevel, @target_id) / 10); + if ($TREASURE_DEBUG) debugmes "TreasureDigAux: player_estimate: @treasure_estimate_team=" + @treasure_estimate_team; + end; + +// Emit few collateral items spawner +OnCollateral1: + if ($TREASURE_DEBUG) debugmes "OnCollateral1"; + setarray .@items1[0], SulphurPowder, IronPowder, BlackScorpionStinger, TreasureKey, Bone, Skull; + set .@itemID, .@items1[rand(getarraysize(.@items1))]; // random collateral + if ($TREASURE_DEBUG) debugmes "OnCollateral1 .@itemID=" + .@itemID; + makeitem .@itemID, 1, getmap(), rand(POS_X-2,POS_X+2), rand(POS_Y-2,POS_Y+2); + end; + +// Emit plenty of collateral items spawner (treasure reward mode) +OnCollateral10: + if ($TREASURE_DEBUG) debugmes "OnCollateral10"; + setarray .@items10[0], Pearl, Sapphire, Amethyst, GoldenTooth, GoldOre, CoinBag; + set .@count, 0; + goto L_RandomItems; + +L_RandomItems: + set .@itemID, .@items10[rand(getarraysize(.@items10))]; // random collateral + makeitem .@itemID, 4+rand(16), getmap(), rand(POS_X-3,POS_X+3), rand(POS_Y-3,POS_Y+3); + set .@count, .@count + 1; + if (.@count < 25) goto L_RandomItems; + end; + +// Hand over rewards + extra "collateral" +// This handler invoked on digger who initiated digging session and won. +OnMainBooty: + addtimer 0, "TreasureDigAux::OnCollateral10"; + gmlog strcharinfo(0) + " found treasure!"; + wgm strcharinfo(0) + " found treasure!"; + getitem $TREASURE_REWARD, 1; + message strcharinfo(0), "Treasure Hunt : Success! You found [" + getitemlink($TREASURE_REWARD) + "]"; + set $TREASURE_REWARD, 0; // Deny re-runs, treasure acquired + end; + +OnInit: + end; +} diff --git a/world/map/npc/items/maps.txt b/world/map/npc/items/maps.txt index 29d54e7d..c7f33d83 100644 --- a/world/map/npc/items/maps.txt +++ b/world/map/npc/items/maps.txt @@ -1,5 +1,6 @@ function|script|readMap -{ +{ // call Treasure Hunt quest. If quest handled use, skip message. See "treasure_hunt.txt" + if (call("treasure_try_map", @MapName$)) goto L_Return; message strcharinfo(0), "You have no clue how to use this item yet."; goto L_Return; diff --git a/world/map/npc/items/shovel.txt b/world/map/npc/items/shovel.txt index 8dcbd175..7023f2ec 100644 --- a/world/map/npc/items/shovel.txt +++ b/world/map/npc/items/shovel.txt @@ -1,5 +1,7 @@ function|script|useShovel -{ +{ // call Treasure Hunt quest. If quest handled use, skip message. See "treasure_hunt.txt" + if (call("treasure_try_shovel", @ShovelName$)) goto L_Return; + // More quests can be plugged in here. message strcharinfo(0), "You have no clue how to use this item yet."; goto L_Return; diff --git a/world/map/npc/scripts.conf b/world/map/npc/scripts.conf index b2565af8..66606bd8 100644 --- a/world/map/npc/scripts.conf +++ b/world/map/npc/scripts.conf @@ -37,6 +37,7 @@ npc: npc/functions/ghost.txt npc: npc/functions/vault.txt npc: npc/functions/global_event_handler.txt npc: npc/functions/teleport_manager.txt +npc: npc/functions/treasure_hunt.txt npc: npc/functions/spawns_on_mobkill.txt // Item Functions |