// TMW-2 Script // Author: // Jesusalva // Description: // GM Bot for the Monster King. // VARIABLES // $GAME_STORYLINE - Current Storyline status // $@MK - Monster King Game ID // $@MK_SCENE - Current event being handled by the Monster King // $MK_TEMPVAR - Temporary Variable // $@MK_THROTTLE - Event Throttler // // Storyline statuses: // 0 - The Monster King is inactive (leading sieges to Hurnscald and Nivalis) // 1 - The Monster King is known by players and is giving them a month break // 2 - The Monster King is currently sieging towns at random // 3 - The Monster King is preparing to perfom the Rite and Lightbringer seeks // a wielder // 4 - The Rite is CONCLUDED. Players must walk to MK evil lair and fight. // 5 - The Monster King is dead. Or something. Depends on players. // // $MK_TEMPVAR meaning depends on GAME STORYLINE // GS 0 // Ignored // GS 1 // Tracks the day since 1970 when the town was cleared. A month break. // GS 2 // Player score (1pt per Lieutenant, 10pts per Colonel) // Affects the end of Game Story 2 and begin of Game Story 3 // Because we must wait players... // GS 3 // Number of successful Fortress Town breaches // GS 4 // Inheirs stage 3 000-0,0,0,0 script Monster King NPC_HIDDEN,{ OnSlaveDie: end; OnBourneAgain: // Reset aggro $@MK_AGGRO=0; if (playerattached()) { channelmes("#world", strcharinfo(0)+" did an act worth of notice."); dispbottom l("Oh well, this sucks, but that was only an illusion."); dispbottom l("The real Monster King is probably on his fortress. It'll take more than that to take him down."); if ($REBIRTH_WINNER$ == "" && TOP3AVERAGELVL() < 100) getexp min(641500, BaseLevel**3), 0; else Mobpt+=max(13500, rand2(10000, BaseLevel*90)); Mobpt = Mobpt + 165; //$MOST_HEROIC$=strcharinfo(0); } // We need to start over .bar=true; OnInit: $@MK=monster("boss", 45, 45, "The Monster King", MonsterKing, 1, "Monster King::OnBourneAgain"); if (!.bar) { // Variables which other NPCs must take in account $@MK_AGGRO=0; $@MK_SCENE=0; } else { .bar=false; } // Variables only for this NPC .users=getusers(1); .nearby=getusers(8); .mp$="boss"; .aid=200000; .cid=150002; // Constants // We should jump straight to loop (it runs every 90 seconds) OnTimer90000: // Regenerate some data, and kill spurious mobs .users=getusers(1); if (mobcount(.mp$, "Monster King::OnSlaveDie")) { announce ("Monster King: Noobs, you are all a bunch of noobs!"), bc_map|bc_npc; killmonster(.mp$, "Monster King::OnSlaveDie"); } // We are on an event, so skip this loop if ($@MK_SCENE || $@GM_EVENT) { initnpctimer; end; } // The Monster King is online. This loop is not needed if (isloggedin(.aid, .cid)) { if (!$@MK_SCENE) unitwarp($@MK, "boss", 45, 45); else rodex_sendmail(.cid, "MKBot", "Running Event", "An event is currently running by the MK Bot. Please logout and suppress it."); initnpctimer; } // Raise aggro (1 pt per 2 users) $@MK_AGGRO+=(.users/2); // Mana Stone if (.mp$ == "011-1") enablenpc "Mana Stone"; // The Monster King will not move anymore because story if ($GAME_STORYLINE == 0 || $GAME_STORYLINE >= 5) { if (.mp$ != "boss") unitwarp($@MK, "boss", 45, 45); initnpctimer; end; } // Select a random map. Never shows up at Candor and cities, nor indoors. Not all maps either. setarray .@m$, "boss", "boss", "001-1", "001-3", "001-4", "001-5", "001-6", "001-7", "001-10", "003-1", "003-1-3", "004-1", "004-2", "007-1", "009-1", "010-1", "010-1-1", "010-2", "011-1", "012-1", "014-1", "014-2", "014-3", "014-4", "014-5", "015-1", "015-2", "015-3", "015-5", "018-1-1", "018-2", "018-3", "018-4", "018-4-1", "019-1", "019-2", "019-4", "020-1", "021-1", "022-1", "023-1"; .mp$=any_of(.@m$); // Try to warp randomly, up to 30 attempts .@e=0; .@x=0; .@y=0; .@mx=getmapinfo(MAPINFO_SIZE_X, .mp$)-20; .@my=getmapinfo(MAPINFO_SIZE_Y, .mp$)-20; do { if (.@e >= 30) { .mp$="boss"; .@x=45; .@y=45; break; } .@x = rand2(20, .@mx); .@y = rand2(20, .@my); .@e+=1; } while (!checknpccell(.mp$, .@x, .@y, cell_chkpass)); if (!checknpccell(.mp$, .@x, .@y, cell_chkpass)) { Exception("mk.bot runtime error: GM_ERR_128 highlight @Jesusalva", RB_DEBUGMES|RB_IRCBROADCAST); .mp$="boss"; .@x=45; .@y=45; } // Monster King will not warp around for sightseeing if he is threatened if ($GAME_STORYLINE > 2 && $@MK_AGGRO < 150) { .mp$="boss";.@x=45;.@y=45; } unitwarp($@MK, .mp$, .@x, .@y); sleep(50); // For some reason or other, adding sleep(norid) and sleep2(rid). .nearby=getusers(8); // Handle Mana Stone if (.mp$ == "011-1") disablenpc "Mana Stone"; // Debug markers if ($@GM_OVERRIDE) debugmes "Monster King (bot): "+.mp$+" ("+.@x+", "+.@y+")"; // If too few players are online, we don't need an event AT ALL! if (.users < rand2(2,4)) { initnpctimer; end; } // Siege events (req. 700 aggro, 3 users, and 75% chances to begin) if ($@MK_AGGRO >= ($GAME_STORYLINE == 2 ? 700 : 2100) && .users >= 3 && rand2(0,100) < 75 && is_between(1, 4, $GAME_STORYLINE) && $@MK_THROTTLE < gettimetick(2)){ // Delta handles the compulsory wait time between waves. // 7 hours normally, 24 hours if the army is in disarray. .@delta=7; $@SIEGE_ABORTED = false; if ($GAME_STORYLINE >= 3) .@delta=24; // Tulimshar if (compare(.mp$, "003-")) { announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc; $@MK_THROTTLE=gettimetick(2)+.@delta*60*60; $@MK_SCENE=MK_SIEGE_TULIM; donpcevent("Lieutenant Dausen::OnMKSiege"); } // Halinarzo else if (compare(.mp$, "009-")) { announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc; $@MK_THROTTLE=gettimetick(2)+.@delta*60*60; $@MK_SCENE=MK_SIEGE_HALIN; donpcevent("Lieutenant Jacob::OnMKSiege"); } // Hurnscald else if (compare(.mp$, "012-")) { announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc; $@MK_THROTTLE=gettimetick(2)+.@delta*60*60; $@MK_SCENE=MK_SIEGE_HURNS; donpcevent("#HurnscaldSiege::OnMKSiege"); } // Nivalis else if (compare(.mp$, "020-")) { announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc; $@MK_THROTTLE=gettimetick(2)+.@delta*60*60; $@MK_SCENE=MK_SIEGE_NIVAL; donpcevent("Lieutenant Joshua::OnMKSiege"); } } // If a player is nearby while the Monster King prepares, event may happen // Minimum 90 Aggro if (.nearby > 1 && $@MK_AGGRO >= 90 && ($GAME_STORYLINE == 1 || ($GAME_STORYLINE >= 3 && $@MK_THROTTLE >= gettimetick(2)) )){ // We should decide event kind, but that's NYI announce ("Monster King: I smell humans! Humans must die!"), bc_map|bc_npc; getmapxy(.@m$, .@x, .@y, UNITTYPE_MOB, $@MK); // Spawn stuff areamonster(.@m$, .@x-20, .@y-20, .@x+20, .@y+20, "Monster", ManaGhost, ($@MK_AGGRO/20)+.nearby, "Monster King::OnSlaveDie"); //$@MK_AGGRO=($@MK_AGGRO*$GAME_STORYLINE)/5; $@MK_AGGRO-=80; // Reduce aggro, but do not deplete it } // Maybe, just maybe, game storyline must be updated here if ($GAME_STORYLINE == 1 && $MK_TEMPVAR && $MK_TEMPVAR <= gettimeparam(GETTIME_DAYOFMONTH)) { // Game Story Change: Idle MK -> Active MK kamibroadcast("I can't handle it anymore! NO MORE!", "Monster King"); sleep(2500); kamibroadcast("Come, my minions! Lay siege to towns! LEAVE NO OPPOSITION TO ME!", "Monster King"); sleep(2500); kamibroadcast("Burn, destroy, do whatever you need, until your last breath, my lieutenants and colonels!", "Monster King"); sleep(2500); kamibroadcast("##4 .:: Game Story Instructions on #world ::."); channelmes("#world", "##1 **GAME STORY CHANGE** - The Monster King minions will now attack cities and lay waste to them."); channelmes("#world", "##1 Players must defeat the lieutenants and colonels in order to prevent sieges from continuing."); // Apply the changes $GAME_STORYLINE=2; $MK_TEMPVAR=0; } if ($GAME_STORYLINE == 2 && $MK_TEMPVAR >= MK_SIEGE_TOTALPOWER) { kamibroadcast("##1##BThe Monster King army is in total disarray and disorder!", "Saulc"); sleep(2500); kamibroadcast("##1##BIt's our chance to strike back!", "Saulc"); sleep(2500); // Apply the changes $GAME_STORYLINE=3; $MK_TEMPVAR=0; // In past, we forced 1 month wait. Now we have KW mechs... $MANA_BLVL-=10; // Set level to 20~30 $MANA_JLVL-=5; // Set job level to 15 } // We're done, restart loop timer initnpctimer; end; } // MKAggro(mobID) → Monster King aggro function script MKAggro { // Every 30 levels gives +1 to monster king aggro // Monsters below level 30 do not generate aggro .@aggro=getarg(0, killedrid); .@moblv=strmobinfo(3,.@aggro); .@aggro=min(5, .@moblv / 30); // Cycles of 30 seconds if (@mkaggra+30 > gettimetick(2)) { .@aggro -= @mkaggrb; if (.@aggro <= 0) return; } else { @mkaggrb=0; } // Increase monster king aggro and update ticks $@MK_AGGRO += .@aggro; @mkaggra=gettimetick(2); @mkaggrb=.@aggro + @mkaggrb; return; }